/*
Copyright (C) 1994-1995 Apogee Software, Ltd.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include <dos.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#include "rt_def.h"
#include "watcom.h"
#include "rt_sound.h"
#include "gmove.h"
#include "states.h"
#include "rt_sqrt.h"
#include "rt_actor.h"
#include "rt_main.h"
#include "rt_playr.h"
#include "isr.h"
#include "rt_draw.h"
#include "rt_ted.h"
#include "rt_door.h"
#include "rt_menu.h"
#include "rt_view.h"
#include "rt_com.h"
#include "rt_in.h"
#include "rt_util.h"
#include "rt_game.h"
#include "rt_rand.h"
#include "z_zone.h"
#include "rt_swift.h"
#include "engine.h"
#include "_rt_play.h"
#include "rt_cfg.h"
#include "rt_spbal.h"
#include "rt_floor.h"
#include "develop.h"
#include "rt_msg.h"
#include "rt_debug.h"
#include "sprites.h"
#include "rt_net.h"
#include "rt_dmand.h"
//MED
#include "memcheck.h"


#define FLYINGZMOM  350000


#if (DEVELOPMENT == 1)
#include "rt_str.h"
#endif

specials CurrentSpecialsTimes =
      {
      60*VBLCOUNTER, // god
      60*VBLCOUNTER, // dog
      20*VBLCOUNTER, // shrooms
      20*VBLCOUNTER, // elasto
      60*VBLCOUNTER, // asbestos vest
      60*VBLCOUNTER, // bullet proof vest
      GASTICS, // gas mask
      60*VBLCOUNTER, // mercury mode

      300*VBLCOUNTER, // god respawn
      60*VBLCOUNTER, // dog respawn
      60*VBLCOUNTER, // shrooms respawn
      60*VBLCOUNTER, // elasto respawn
      60*VBLCOUNTER, // asbestos vest respawn
      60*VBLCOUNTER, // bullet proof vest respawn
      60*VBLCOUNTER, // gas mask respawn
      60*VBLCOUNTER  // mercury mode respawn
      };

int GRAVITY = NORMAL_GRAVITY;

ROTTCHARS characters[5]={
   {0x2100,0x4800,100,2,25},  // Taradino Cassatt
   {0x2200,0x5200,85,3,32},   // Thi Barrett
   {0x1f00,0x4000,150,3,20},  // Doug Wendt
   {0x2300,0x5500,70,2,33},   // Lorelei Ni
   {0x2000,0x4400,120,3,25}}; // Ian Paul Freeley

static const int TD = MINACTORDIST+0x1000;
static const int STRAFEAMOUNT = ((KEYBOARDNORMALTURNAMOUNT >> 10) + (KEYBOARDNORMALTURNAMOUNT >> 12));


static const int GODYZANGLE     = -(9*FINEANGLES/360);
static const int DOGYZANGLE     =  (4*FINEANGLES/360);
static const int SHROOMYZANGLE  =  (15*FINEANGLES/360);
static const int FALLINGYZANGLE = -(15*FINEANGLES/360);
static const int NORMALYZANGLE  = 0;


/*
=============================================================================

			GLOBAL VARIABLES

=============================================================================
*/

int controlbuf[3];
int buttonbits;
extern _2Dpoint LASTSOUND;
//
// player state info
//

statobj_t      *DEADPLAYER[MAXDEAD];
int            NUMDEAD;
int            lastpolltime;

statobj_t      *BulletHoles[MAXBULLETS];
int            BulletHoleNum;

objtype        *PLAYER[MAXPLAYERS],*player;
playertype     PLAYERSTATE[MAXPLAYERS],*locplayerstate;

gametype       gamestate;

boolean        godmode = false;

boolean       missilecam=false;
objtype       * missobj=NULL;
// Player control variables

int KX = 0;
int KY = 0;
int MX = 0;
int MY = 0;
int JX = 0;
int JY = 0;
int CX = 0;
int CY = 0;
boolean vrenabled = false;
int VX = 0;
int VY = 0;

int oldcyberx = 0;
int oldcybery = 0;
int CYBERDEADRANGE = 6000;
boolean CYBERLOOKUP,CYBERLOOKDOWN;

int leftmom = 0;
int rightmom = 0;
int lastmom = 0;
int first    = 1;

int pausedstartedticcount;
boolean RefreshPause = true;

boolean  buttonpoll[NUMBUTTONS];

int      buttonscan[NUMBUTTONS] = {sc_Control, sc_Alt, sc_RShift, sc_Space,
											  sc_PgUp,sc_PgDn,sc_Enter,sc_Delete,
                                   sc_Home,sc_End,sc_1,sc_2,sc_3,sc_4,
                                   sc_CapsLock, sc_F12,
                                   sc_Comma,sc_Period,sc_BackSpace,sc_A,
                                   sc_UpArrow, sc_RightArrow,
                                   sc_DownArrow, sc_LeftArrow,
                                   sc_Tab, sc_T, sc_Z };

int      joyxmax = 0, joyymax = 0, joyxmin = 0, joyymin = 0;

int      buttonmouse[6] = {bt_attack, bt_strafe, di_north,
                           bt_nobutton, bt_use, bt_nobutton };

int      buttonjoy[8] = {bt_attack, bt_strafe, bt_run, bt_use,
                         bt_nobutton, bt_nobutton, bt_nobutton, bt_nobutton };

williamdidthis FREE = {84,5,0,0,9,{{done,2,1},{done,2,2},{done,2,3},
  {done,2,4},{done,2,5},{done,2,6},{done,2,7},{done,2,8},
  {reset,2,9}}};

williamdidthis DOGSCRATCH = {128,5,0,0,4,{{done,2,8},{at_pulltrigger,2,9},{done,2,10},
                             {reset,2,11}}};

williamdidthis DOGLICK =    {128,5,0,0,4,{{done,2,4},{done,2,5},{done,2,6},
                             {reset,2,7}}};


williamdidthis WEAPONS[MAXWEAPONS] =

{
 {100,-1,10,0x2000l,3,{{at_pulltrigger,4,1},{done,4,2},{reset,4,0}}}, //single pistol
 {100,-1,10,0x2000l,6,{{at_pulltrigger,2,1},{done,2,2},{done,2,3},
						{at_pulltrigger,2,4},{done,2,5},{reset,2,3}}}, // double pistol
 {70,-1,10,0x2000l,2,{{at_pulltrigger,2,1},{reset,1,2}}}, //mp 40
 {80,5,10,0x50000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //bazooka
 {80,5,10,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //firebomb
 {80,5,10,0x50000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //heatseeker
 {80,5,10,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //drunk
 {80,5,7,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,2},{reset2,6,0}}}, // firewall
 {125,5,7,0x10000l,7,{{done,3,1},{done,3,2},{done,3,3},{done,3,4},
						  {at_missileweapon,3,5},{done,3,6},{reset,3,7}}},	//GODHAND

#if (SHAREWARE == 0)
 {80,5,7,0x10000l,4,{{at_missileweapon,2,1},{done,2,2},{reset,2,3},{reset2,6,0}}}, //split
 {80,5,7,0x10000l,9,{{done,5,1},{done,5,2},{done,5,3},{done,5,4},
						{at_missileweapon,10,5},{done,5,4},{done,5,3}, // kes
						{done,5,2},{reset,5,1}}},
 {200,5,7,0x10000l,6,{{done,1,1},{done,1,2},{at_pulltrigger,1,3},{at_pulltrigger,1,4},
						  {at_pulltrigger,1,5},{reset,1,6}}},	//BAT
 {128,5,7,0x10000l,3,{{done,2,1},{at_pulltrigger,2,2},{reset,2,3}}}
#endif
};



/*
=============================================================================

					LOCAL FUNCTION PROTOTYPES and VARIABLES

=============================================================================
*/

void     CheckPlayerSpecials(objtype * ob);
void     CheckWeaponStates(objtype * ob);
boolean  CheckSprite (statobj_t* ,int *);
void     T_Tag (objtype *ob);
void     T_Player (objtype *ob);
void     T_BatBlast(objtype*ob);
void     T_Attack (objtype *ob);
void     T_Free (objtype *ob);
void     T_DogUse (objtype *ob);
void     PlayerMove(objtype * ob);
void     Thrust (objtype * ob);
void     CheckWeaponChange (objtype * ob);
void     PlayerMissileAttack(objtype* );
void     Cmd_Use(objtype*);
//void     ComError (char *error, ...);

statetype s_free = {false,0,0,T_Free,NULL,&s_free};
statetype s_inelevator = {false,0,420,T_Player,NULL,&s_player};

#if (SHAREWARE == 0)
statetype s_dogwait = {true,SERIALDOG_W11,50,T_Player,SF_DOGSTATE,&s_serialdog};

statetype s_doguse = {true,SERIALDOG_W11,140,T_DogUse,SF_DOGSTATE,&s_serialdog};
statetype s_doglick = {true,SERIALDOG_W11,0,T_DogLick,SF_DOGSTATE,&s_doglick};
#endif

statetype s_tag = {false,CASSATT_S1,20,T_Tag,NULL,&s_player};

static SWIFT_3DStatus SWIFTStatus;

//
// curent user input
//

static int turnheldtime;
static int turnaround = 0;
static int turnaroundtime;

//
// Double Click variables
//

static int  DoubleClickTimer[ 3 ]   = { 0 };
static byte DoubleClickCount[ 3 ]   = { 0 };
static byte DoubleClickPressed[ 3 ] = { false };
static int  JoyDblClickTimer[ 4 ]   = { 0 };
static byte JoyDblClickCount[ 4 ]   = { 0 };
static byte JoyDblClickPressed[ 4 ] = { false };


static int PlayerRecording=-1;
static int nettics;

/*
===============
=
= LoadPlayer
=
===============
*/
void LoadPlayer ( void )
{
	memset (locplayerstate->buttonstate, 0, sizeof(locplayerstate->buttonstate));
   locplayerstate->anglefrac=player->angle<<ANGLEBITS;
   areabyplayer[player->areanumber]=true;
	ConnectAreas();
}


int MaxHitpointsForCharacter(playertype*pstate)
{
   if (BATTLEMODE && (gamestate.BattleOptions.HitPoints != bo_character_hitpoints))
      {
      return( gamestate.BattleOptions.HitPoints );
      }
   return characters[pstate->player].hitpoints;
}

void InitializeWeapons(playertype*pstate)
{


#if (SHAREWARE == 0)
 if (gamestate.SpawnEluder)
	{pstate->new_weapon = pstate->weapon = pstate->missileweapon = wp_dog;
	 pstate->oldweapon = pstate->oldmissileweapon = wp_dog;
	 pstate->bulletweapon = -1;
	 pstate->HASBULLETWEAPON[wp_pistol] = 0;
	 pstate->HASBULLETWEAPON[wp_twopistol] = 0;
	 pstate->HASBULLETWEAPON[wp_mp40] = 0;
	}
 else
#endif
	{if (gamestate.PlayerHasGun[pstate-&PLAYERSTATE[0]])
		 {pstate->new_weapon = pstate->weapon = pstate->oldweapon =
		  pstate->bulletweapon = wp_pistol;
		  pstate->HASBULLETWEAPON[wp_pistol] = 1;
		  pstate->HASBULLETWEAPON[wp_twopistol] = 0;
		  pstate->HASBULLETWEAPON[wp_mp40] = 0;
		  pstate->missileweapon = pstate->oldmissileweapon = -1;
		 }
	 else
		 {pstate->new_weapon = pstate->weapon = pstate->oldweapon =
		  pstate->bulletweapon = -1;
		  pstate->HASBULLETWEAPON[wp_pistol] = 0;
		  pstate->HASBULLETWEAPON[wp_twopistol] = 0;
		  pstate->HASBULLETWEAPON[wp_mp40] = 0;
		  pstate->missileweapon = pstate->oldmissileweapon = -1;
		 }
	}


 pstate->ammo = -1;
}

void ResetPlayerstate(playertype*pstate)
{

 pstate->batblast = 0;
 pstate->poweruptime = pstate->protectiontime = 0;
 pstate->NETCAPTURED = 0;
 MISCVARS->NET_IN_FLIGHT = 0;
 pstate->weaponuptics = 0;
 pstate->weapondowntics = 0;
 if ((insetupgame==false) || NewGame)
	 pstate->health = MaxHitpointsForCharacter(pstate);
 pstate->keys = 0;

 // Give players all the keys in battle game

 if ( BATTLEMODE )
    {
    pstate->keys = 0x0f;
    }
 pstate->attackframe = pstate->attackcount =
 pstate->weaponframe = 0;
 if (gamestate.battlemode == battle_Tag)
	pstate->weaponheight = TAGHANDHEIGHT;
 else
	pstate->weaponheight = 0;
 pstate->heightoffset = pstate->oldheightoffset = 0;
 if (gamestate.SpawnEluder)
	pstate->playerheight = 40;
 else
	pstate->playerheight = characters[pstate->player].height;
 pstate->falling = false;
 memset (pstate->buttonstate, 0, sizeof(pstate->buttonstate));
 SetPlayerHorizon(pstate,NORMALYZANGLE);
}




/*
===============
=
= SetupPlayerobj
=
===============
*/
void SetupPlayerobj (int tilex, int tiley, int dir, objtype * ob)
{
	playertype *pstate;

	M_LINKSTATE(ob,pstate);

	ob->obclass = playerobj;
	ob->tilex = tilex;
	ob->tiley = tiley;
	actorat[tilex][tiley] = ob;
	ob->areanumber = MAPSPOT(tilex,tiley,0)-AREATILE;
	MakeLastInArea(ob);
	ob->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
	ob->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
	ob->z = PlatformHeight(tilex,tiley);
   if ((ob->z == -10) || DiskAt(tilex,tiley))
     ob->z = 0;

	ob->angle = (1-dir)*ANG90;
	ob->which = ACTOR;
	Fix(ob->angle);
   ob->yzangle = 0;

	ob->dir   = angletodir[ob->angle];
	ob->flags = (FL_SHOOTABLE|FL_ABP|FL_BLOCK|FL_COLORED);
	ob->drawx=ob->x;
	ob->drawy=ob->y;
	ob->hitpoints = pstate->health;
	pstate->anglefrac= (ob->angle<<ANGLEBITS);
	pstate->angle=0;
	areabyplayer[ob->areanumber]=true;


	if (ob == player)
		{
		playerdead=false; // local player dead flag
		}
	if (!gamestate.SpawnEluder)
	  ob->shapeoffset = pstate->player*REMOTEOFFSET;

	memset (pstate->buttonstate, 0, sizeof(pstate->buttonstate));
   if (SCREENEYE != NULL)
      {
      NewState(SCREENEYE,&s_megaremove);
      SCREENEYE = NULL;
      }
}



void SetShapeoffset(objtype*ob)
{playertype *pstate;

 M_LINKSTATE(ob,pstate);
 ob->shapeoffset = pstate->player*REMOTEOFFSET;
 ob->flags |= FL_COLORED;
 ob->flags &= ~FL_DYING;

}


/*
===============
=
= RevivePlayerobj
=
===============
*/
void RevivePlayerobj (int tilex, int tiley, int dir, objtype*ob)
{
	playertype *pstate;
	statetype *tstate;

	M_LINKSTATE(ob,pstate);
	tstate = ob->state;
	RemoveFromArea(ob);
	TurnActorIntoSprite(ob);
	if ((LASTSTAT->z < nominalheight) && (!IsPlatform(LASTSTAT->tilex,LASTSTAT->tiley)))
      {
      SpawnParticles(ob,GUTS,10 + gamestate.difficulty);
		RemoveStatic(LASTSTAT);
      }
	else
	  {if (DEADPLAYER[NUMDEAD])
			RemoveStatic(DEADPLAYER[NUMDEAD]);
		DEADPLAYER[NUMDEAD] = LASTSTAT;
		LASTSTAT->linked_to = NUMDEAD;
		NUMDEAD = (NUMDEAD+1)&(MAXDEAD-1);
	  }

	ob->state = tstate;

	SetupPlayerobj (tilex, tiley, dir, ob);
	ConnectAreas();

	ResetPlayerstate(pstate);
	InitializeWeapons(pstate);
   SD_PlaySoundRTP(SD_PLAYERSPAWNSND,ob->x,ob->y);
	if (!gamestate.SpawnEluder)
      {
      ob->shapeoffset = 0;
      ob->flags &= ~FL_COLORED;
      ob->flags |= FL_DYING;
      NewState(ob,&s_respawn1);
      if (gamestate.battlemode == battle_Tag)
         {
         if (BATTLE_Team[ob->dirchoosetime] == BATTLE_It)

            {
            pstate->missileweapon = pstate->oldweapon = pstate->new_weapon =
            pstate->oldmissileweapon = pstate->weapon = wp_godhand;
            pstate->bulletweapon = -1;
            ob->flags |= FL_DESIGNATED;
            }
         else
            {
            pstate->weaponheight = 0;
            }
         }
		}
#if (SHAREWARE == 0)
	else
      NewState(ob,&s_serialdog);
#endif
	if (ob==player)
		DrawPlayScreen(false);
   ob->momentumx = ob->momentumy = ob->momentumz = 0;
}


/*
===============
=
= SpawnPlayerobj
=
===============
*/
void SpawnPlayerobj (int tilex, int tiley, int dir, int playerindex)
{
 playertype *pstate;

	pstate = &PLAYERSTATE[playerindex];

	GetNewActor();
	MakeActive(new);

	// Set player number

	new->dirchoosetime = playerindex;

	// Save off if local player

	if (playerindex==consoleplayer)
		player=new;

	PLAYER[playerindex] = new;

	SetupPlayerobj (tilex, tiley, dir, new);

	if (!gamestate.SpawnEluder)
		NewState(new,&s_player);
#if (SHAREWARE == 0)
   else
      NewState(new,&s_serialdog);
#endif


}

/*
===============
=
= SetupBulletHoleLink
=
===============
*/
void SetupBulletHoleLink (int num, statobj_t * item)
{
   BulletHoles[num] = item;
}

/*
===============
=
= SpawnBulletHole
=
===============
*/
void SpawnBulletHole (int x, int y, int z)
{
   if (M_ISDOOR(x>>16,y>>16))
      return;
   if (BulletHoles[MISCVARS->BulletHoleNum])
      RemoveStatic(BulletHoles[MISCVARS->BulletHoleNum]);
   SpawnInertStatic(x,y,z,stat_bullethole);
	BulletHoles[MISCVARS->BulletHoleNum]=LASTSTAT;
   LASTSTAT->linked_to=MISCVARS->BulletHoleNum;
	MISCVARS->BulletHoleNum = (MISCVARS->BulletHoleNum+1)&(MAXBULLETS-1);
}




void SpawnGunSmoke(int x, int y, int z, int angle, int bullethole)

{
	int chance;

	if ((x<=0) || (y<=0))
      {
      SoftError("SpawnGunSmoke: xy below angle=%ld\n",angle);
      return;
      }

   if ((bullethole!=0) && (z>=-32) && (z<=maxheight))
      switch (bullethole)
         {
         case 1:
            SpawnBulletHole(x-BULLETHOLEOFFSET,y,z);
            break;
         case 2:
            SpawnBulletHole(x+BULLETHOLEOFFSET,y,z);
            break;
         case 3:
            SpawnBulletHole(x,y-BULLETHOLEOFFSET,z);
            break;
         case 4:
            SpawnBulletHole(x,y+BULLETHOLEOFFSET,z);
            break;
         case 5:
            SpawnBulletHole(x,y,z);
            break;
         default:
            Error("Invalid bullethole value\n");
            break;
         }

   SpawnInertActor(x,y,z);

   NewState(new,&s_gunsmoke1);

   if (angle < ANGLES/4)
	 {if ((angle < (3*ANGLES/16)) && (angle > (ANGLES/16)))
		chance = 128;
	  else
		chance = 20;
	 }
	else if (angle < ANGLES/2)
	 {if ((angle < (7*ANGLES/16)) && (angle > (5*ANGLES/16)))
		chance = 128;
	  else
		chance = 20;
	 }
	else if (angle < 3*ANGLES/4)
	 {if ((angle < (11*ANGLES/16)) && (angle > (9*ANGLES/16)))
		chance = 128;
	  else
		chance = 20;
	 }
	else
	 {if ((angle < (15*ANGLES/16)) && (angle > (13*ANGLES/16)))
		chance = 128;
	  else
		chance = 20;
	 }

	if (RandomNumber("Wall ricochet check",0)<chance)
	 {int rand;

	  rand = RandomNumber("Spawn Ricochet Sound in SpawnGunSmoke",0);
	  if (rand < 80)
		 SD_PlaySoundRTP(SD_RICOCHET1SND,new->x,new->y);
	  else if (rand < 160)
		 SD_PlaySoundRTP(SD_RICOCHET2SND,new->x,new->y);
	  else
		 SD_PlaySoundRTP(SD_RICOCHET3SND,new->x,new->y);
	 }
}

void  SpawnBlood(objtype * ob, int angle)
   {

   SpawnInertActor(ob->x-(costable[angle]>>5),
                   ob->y+(sintable[angle]>>5),ob->z);

   NewState(new,&s_bloodspurt1);

   if ((new->x<=0) || (new->y<=0))
	   Error("SpawnBlood: bad x,y obj->obclass=%ld\n",ob->obclass);
   }

void  SpawnMetalSparks(objtype * ob, int angle)
   {
   int rand,dispx=0,dispy=0;


   if (ob->which == ACTOR)
      {
      dispx = ob->momentumx;
      dispy = ob->momentumy;
      }

   SpawnInertActor(ob->x-(costable[angle]>>3)+dispx,
                   ob->y+(sintable[angle]>>3)+dispy,ob->z);

   if (GameRandomNumber("Spawn Metal Sparks",0)<128)
	  NewState(new,&s_hitmetalactor1);
	else
	  NewState(new,&s_hitmetalwall1);

	rand = RandomNumber("Spawn Ricochet Sound",0);
	if (rand < 80)
	 SD_PlaySoundRTP(SD_RICOCHET1SND,new->x,new->y);
	else if (rand < 160)
	 SD_PlaySoundRTP(SD_RICOCHET2SND,new->x,new->y);
	else
	 SD_PlaySoundRTP(SD_RICOCHET3SND,new->x,new->y);
	if ((new->x<=0) || (new->y<=0))
	   Error("SpawnMetalSparks: bad x,y obj->obclass=%ld\n",ob->obclass);
}

/*
===============
=
= UnTargetActor ( objtype * target )
=
===============
*/
void UnTargetActor ( objtype * target )
{
   int i;

   for (i=0;i<numplayers;i++)
      {
      if (PLAYERSTATE[i].guntarget==target)
         {
         PLAYERSTATE[i].guntarget=NULL;
         SetNormalHorizon(PLAYER[i]);
         }
      }
}



//=============================================================

int GetWeaponForItem(int itemnumber)
   {
   switch (itemnumber)
      {


      case  stat_twopistol:
         return wp_twopistol;

      case  stat_mp40:
         return wp_mp40;

      case  stat_bazooka:
         return wp_bazooka;

      case  stat_heatseeker:
         return wp_heatseeker;

      case  stat_drunkmissile:
         return wp_drunk;

      case  stat_firebomb:
         return wp_firebomb;

      case  stat_firewall:
         return wp_firewall;

      case  stat_godmode:
         return wp_godhand;

#if (SHAREWARE == 0)


      case  stat_splitmissile:
         return wp_split;

      case  stat_kes:
         return wp_kes;

      case  stat_bat:
         return wp_bat;


      case  stat_dogmode:
         return wp_dog;
#endif
      }
    return 0;
   }


int GetItemForWeapon(int weapon)
   {
   switch (weapon)
      {

      case wp_twopistol:
         return stat_twopistol;

      case  wp_mp40:
         return stat_mp40;

      case  wp_bazooka:
         return stat_bazooka;

      case  wp_heatseeker:
         return stat_heatseeker;

      case  wp_drunk:
         return stat_drunkmissile;

      case  wp_firebomb:
         return stat_firebomb;

      case  wp_firewall:
         return stat_firewall;

      case  wp_godhand:
         return stat_godmode;

#if (SHAREWARE == 0)

      case  wp_split:
         return stat_splitmissile;

      case  wp_kes:
         return stat_kes;

      case  wp_bat:
         return stat_bat;


      case  wp_dog:
         return stat_dogmode;
#endif
      }
    return -1;
   }



#define MF_SINGULAR 0x01

missile_stats PlayerMissileData[13] =

    {
     {0,0,0,0,0},
     {0,0,0,0,0},
     {0,0,0,0,0},

     {&s_p_bazooka1,0x6000,p_bazookaobj,0x7000,MF_SINGULAR},
     {&s_p_bazooka1,0x8000,p_heatseekobj,0x7000,MF_SINGULAR},
     {&s_p_bazooka1,0x6000,p_drunkmissileobj,0x7000,0},
     {&s_p_bazooka1,0x8000,p_firebombobj,0x7000,MF_SINGULAR},
     {&s_p_grenade,0x4000,p_firewallobj,0x8000,0},
     {&s_godfire1,0x3800,p_godballobj,0x8000,0},
     {&s_p_bazooka1,0x8000,p_splitmissileobj,0x7000,MF_SINGULAR},
#if (SHAREWARE == 0)
     {&s_kessphere1,0xc000,p_kesobj,0x5000,MF_SINGULAR},
#else
     {0,0,0,0,0},
#endif
     {0,0,0,0,0},
     {0,0,0,0,0}

    };


void MissileAutoTarget(objtype *ob,missile_stats *mdata)
   {
   int dx,dy,angle,mindist,currdist,magangle,saveangle,
       xydist,dz,yzangle,oldyzangle,saveyzangle;
   objtype *target,*temp;

   mindist = 0x7fffffff;
   target = NULL;
   for(temp = firstactive;temp;temp=temp->nextactive)
      {
      if (temp == ob)
         continue;
      if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
         continue;
      if (!CheckLine(ob,temp,SHOOT))
         continue;

      dx = temp->x-ob->x;
      dy = ob->y-temp->y;
      dz = ob->z-temp->z;
      xydist = FindDistance(dx,dy);
      yzangle = atan2_appx(xydist,dz<<10);

      angle = atan2_appx(dx,dy);

      magangle = abs(ob->angle - angle);
      if (magangle > VANG180)
         magangle = ANGLES - magangle;

      if (magangle > ANGLESDIV8)
         continue;

      currdist = FindDistance(ob->x-temp->x,ob->y-temp->y);
      if (currdist < mindist)
         {
         mindist = currdist;
         target = temp;
         saveangle = angle;
         saveyzangle = yzangle;
         }
      }

   if (target)
      {
      oldyzangle = ob->yzangle;
      ob->yzangle = saveyzangle;
      SpawnMissile(ob,mdata->obclass,mdata->speed,saveangle,
                   mdata->state,mdata->offset);
      ob->yzangle = oldyzangle;
      }

   else if (ob->flags&FL_GODMODE)
      {
      int saveangle;

      saveangle=ob->yzangle;
      ob->yzangle -= GODYZANGLE;
      Fix(ob->yzangle);
      SpawnMissile(ob,mdata->obclass,mdata->speed,
                   ob->angle,mdata->state,mdata->offset);
      ob->yzangle=saveangle;
      }
   else
      SpawnMissile(ob,mdata->obclass,mdata->speed,ob->angle,
                   mdata->state,mdata->offset);

  }


void PlayerMissileAttack(objtype*ob)

   {
   playertype * pstate;
   missile_stats *newmissiledata;
   M_LINKSTATE(ob,pstate);


   MISCVARS->madenoise = true;
   newmissiledata = &PlayerMissileData[pstate->missileweapon];

   // ready to annihilate this poor bastard

   if ((newmissiledata->obclass == p_godballobj) ||
       (newmissiledata->obclass == p_kesobj))
      MissileAutoTarget(ob,newmissiledata);

   else
      {
      SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,ob->angle,
                  newmissiledata->state,newmissiledata->offset);

      if (newmissiledata->obclass == p_drunkmissileobj)
         {
         int i;

         for(i=0;i<4;i++)
            {
            if (!MissileTryMove(new,new->x+new->momentumx,new->y+new->momentumy,new->z))
               {
               new->x = new->drawx = ob->x + (costable[new->angle]>>3);
               new->y = new->drawy = ob->y - (sintable[new->angle]>>3);

               ob->momentumx = -FixedMul(0x5000l,costable[ob->angle]);
               ob->momentumy = FixedMul(0x5000l,sintable[ob->angle]);
               }

            SpawnMissile(ob,newmissiledata->obclass,newmissiledata->speed,ob->angle,
                        newmissiledata->state,newmissiledata->offset);


            }
         }
      }


   if (newmissiledata->flags & MF_SINGULAR)
      PLAYER0MISSILE = new;

   SD_PlaySoundRTP(BAS[new->obclass].fire,ob->x,ob->y);

   // if (new->obclass == p_godballobj)
   //   new->z += 10;

   new->dirchoosetime = 5;
   if (missilecam==true)
      missobj=new;
   if (!MissileTryMove(new,new->x+new->momentumx,new->y+new->momentumy,new->z))
      {
      new->x = new->drawx = ob->x + (costable[new->angle]>>3);
      new->y = new->drawy = ob->y - (sintable[new->angle]>>3);

      ob->momentumx = -FixedMul(0x5000l,costable[ob->angle]);
      ob->momentumy = FixedMul(0x5000l,sintable[ob->angle]);
      }

   }

//====================================================================


boolean InRange (objtype *p, objtype *victim, int distance)
{
	int dx,dy;
	int angle;
	int magangle;

   if (victim->which==SPRITE)
		{
	   dx = ((statobj_t *)victim)->x - p->x;
	   dy = p->y - ((statobj_t *)victim)->y;
      }
   else
      {
	   dx = victim->x - p->x;
	   dy = p->y - victim->y;
      }
	angle = atan2_appx (dx,dy);

	magangle = abs(p->angle - angle);
	if (magangle > VANG180)
		 magangle = ANGLES - magangle;
	if (magangle<(75-(distance>>16)))
		return true;
	else
		return false;
}


void DogAttack(objtype*ob)
   {
   objtype *temp;
   int dx,dy,dz;

   SD_PlaySoundRTP(SD_DOGMODEBITE1SND+(RandomNumber("DogAttack",0)>>7),ob->x,ob->y);
   for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
      {

      if (temp->obclass > b_heinrichobj)
         continue;


      if ((temp == ob) || (temp->obclass == roboguardobj))
         continue;

      if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
         continue;
      if (temp->obclass == collectorobj)
         continue;


      dx = abs(temp->x - ob->x);
      if (dx > 0xc000)
         continue;

      dy = abs(temp->y - ob->y);
      if (dy > 0xc000)
         continue;

      dz = abs(temp->z - ob->z);
      if (dz > (0xc000>>10))
         continue;

      DamageThing(temp,30);
      if (gamestate.violence == vl_excessive)
         SpawnParticles(temp,GUTS,15);
      Collision(temp,ob,-temp->momentumx,-temp->momentumy);
      if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
         BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);

      return;
      }
   }


void DogBlast(objtype*ob)
   {
   int txl,txh,tyl,tyh,radius = 0x70000,x,y,tile;
   objtype*temp;
   statobj_t*tstat;

   txl = ((ob->x - radius)>>TILESHIFT);
   tyl = ((ob->y - radius)>>TILESHIFT);

   txh = ((ob->x + radius)>>TILESHIFT);
   tyh = ((ob->y + radius)>>TILESHIFT);

   if (txl < 1)
      txl = 1;
   if (txh > MAPSIZE-1)
      txh = MAPSIZE-1;
   if (tyl < 1)
      tyl = 1;
   if (tyh > MAPSIZE-1)
      tyh = MAPSIZE-1;

   for(x=txl;x<=txh;x++)
      for(y=tyl;y<=tyh;y++)
         {
         temp = (objtype*)actorat[x][y];

         if (temp && (temp->which == ACTOR) && (temp->flags & FL_SHOOTABLE) &&
             (temp != ob) && (temp->obclass < roboguardobj) &&
             (temp->flags & FL_ABP)
            )
            {
            DamageThing(temp,100);
            if ((temp->hitpoints<=0) && (temp->obclass < roboguardobj))
               {
               MISCVARS->supergibflag = true;
               temp->flags |= FL_HBM;
               }
            Collision(temp,ob,0,0);
            MISCVARS->supergibflag = false;

            if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
               BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);

            }

         tile = tilemap[x][y];
         if ((tile & 0x4000) && (tile & 0x8000))
            {
            maskedwallobj_t * mw;

            mw=maskobjlist[tile&0x3ff];
            if ((mw->flags & MW_SHOOTABLE) && (mw->flags & MW_ABP))
               UpdateMaskedWall(tile&0x3ff);
            }

         tstat = sprites[x][y];
         if (tstat && (tstat->flags & FL_SHOOTABLE) && (tstat->flags & FL_ABP))
               DamageThing(tstat,50);
         }
   }
/*
void DogBlast(objtype*ob)
   {
   int txl,txh,tyl,tyh,radius = 0x70000,x,y,tile;
   objtype*temp;
   statobj_t*tstat;

   txl = ((ob->x - radius)>>TILESHIFT);
   tyl = ((ob->y - radius)>>TILESHIFT);

   txh = ((ob->x + radius)>>TILESHIFT);
   tyh = ((ob->y + radius)>>TILESHIFT);

   if (txl < 1)
      txl = 1;
   if (txh > MAPSIZE-1)
      txh = MAPSIZE-1;
   if (tyl < 1)
      tyl = 1;
   if (tyh > MAPSIZE-1)
      tyh = MAPSIZE-1;

   for(x=txl;x<=txh;x++)
      for(y=tyl;y<=tyh;y++)
         {
         temp = (objtype*)actorat[x][y];

         if (temp && (temp->which == ACTOR) && (temp->flags & FL_SHOOTABLE) &&
            (temp != ob) && (temp->obclass < roboguardobj))
            {
            DamageThing(temp,100);
            if ((temp->hitpoints<=0) && (temp->obclass < roboguardobj))
               {
               MISCVARS->supergibflag = true;
               temp->flags |= FL_HBM;
               }
            Collision(temp,ob,0,0);
            MISCVARS->supergibflag = false;

            if ((temp->obclass == playerobj) && (temp->flags & FL_DYING))
               BATTLE_PlayerKilledPlayer(battle_kill_with_missile,ob->dirchoosetime,temp->dirchoosetime);

            }

         tile = tilemap[x][y];
         if ((tile & 0x4000) && (tile & 0x8000))
            {
            maskedwallobj_t * mw;

            mw=maskobjlist[tile&0x3ff];
            if (mw->flags & MW_SHOOTABLE)
               UpdateMaskedWall(tile&0x3ff);
            }

         tstat = sprites[x][y];
         if (tstat && (tstat->flags & FL_SHOOTABLE))
            DamageThing(tstat,50);
         }
   }
*/

void BatBlast(objtype*ob)
{int angle;
 playertype *pstate;

 M_LINKSTATE(ob,pstate);

 angle = ob->angle - ANGLES/8 + ((++pstate->batblast)*ANGLES/48);
 Fix(angle);
#if (SHAREWARE == 0)
 SpawnMissile(ob,p_bazookaobj,0x6000,angle,&s_batblast1,0xa000);
#endif

}



void BatAttack(objtype*ob)
{objtype *temp,*temp2;
 objtype *grenadetarget;
 statobj_t*tstat;
 int dx,dy,dz,angle,momx,momy,op,magangle;
 int tilexlow,tilexhigh;
 int tileylow,tileyhigh;
 int radius =0x10000;
 int x,y;

 SD_PlaySoundRTP(SD_EXCALISWINGSND,ob->x,ob->y);
 for(temp=firstareaactor[ob->areanumber];temp;temp=temp->nextinarea)
  {if (temp == ob)
	 continue;

   if (temp->flags & FL_DYING)
     continue;

   if ((temp->obclass != grenadeobj) &&
       (!((temp->obclass >= grenadeobj) && (temp->obclass <= p_godballobj))) &&
		 (!(temp->flags & FL_SHOOTABLE) ||
		  (temp->obclass >= roboguardobj))
		)
	 continue;

	dx = abs(temp->x - ob->x);
	dy = abs(temp->y - ob->y);
	dz = abs(temp->z - ob->z);
   if ((dx > 0x10000) || (dy > 0x10000) || (dz > 20))
	 continue;

	magangle = abs(ob->angle - AngleBetween(ob,temp));
	if (magangle > VANG180)
		 magangle = ANGLES - magangle;

	if (magangle > ANGLES/8)
	  continue;


	angle= ob->angle+ANGLES/16;
	Fix(angle);

   if ((temp->obclass >= grenadeobj) && (temp->obclass <= p_godballobj))
     {
      temp->angle += ANGLES/2;
      Fix(temp->angle);
      temp->momentumx = temp->momentumy = temp->momentumz = 0;
      ParseMomentum(temp,temp->angle);
      temp->whatever = ob;
      temp->target = NULL;
      continue;
     }


   else if (temp->obclass != grenadeobj)
	  {momx = FixedMul(0x3000l,costable[angle]);
		momy = -FixedMul(0x3000l,sintable[angle]);
		if (levelheight > 2)
		 {op = FixedMul(GRAVITY,(maxheight-100)<<16) << 1;
		  temp->momentumz = -FixedSqrtHP(op);
		 }
		temp->flags |= FL_NOFRICTION;
		SD_PlaySoundRTP(SD_EXCALIHITSND,ob->x,ob->y);
		if ((gamestate.violence == vl_excessive) && (GameRandomNumber("Bat Gibs",0) < 150))
		  {temp->flags |= FL_HBM;
			DamageThing(temp,50);
		  }
		else
			DamageThing(temp,10);
		if ((temp->flags & FL_HBM) && (temp->hitpoints > 0))
		  temp->flags &= ~FL_HBM;
      Collision(temp,ob,momx,momy);
		if ((temp->obclass == blitzguardobj) && (temp->state == &s_blitzplead7))
		  {temp->shapeoffset += deathshapeoffset[temp->obclass];
			temp->flags |= FL_ALTERNATE;
			NewState(temp,&s_blitzdie3);
			temp->momentumx = temp->momentumy = 0;
		  }
	  }
	else // find target to hit grenade back at
	  {int rand;

		rand = GameRandomNumber("bat/grenade target",0);
		if (rand < 80)
		  {grenadetarget = (objtype*)(temp->whatever); // hit back at george
         GetMomenta(grenadetarget,ob,&(temp->momentumx),&(temp->momentumy),&(temp->momentumz),0x3000);
		  }
		else if (rand < 160) // hit back at first eligible
		  {

			for(temp2 = firstareaactor[ob->areanumber];temp2;temp2 = temp2->nextinarea)
				{magangle = abs(ob->angle-AngleBetween(ob,temp2));
				 if (magangle > VANG180)
					 magangle = ANGLES - magangle;

				 if (magangle > ANGLES/8)
					 continue;
             GetMomenta(temp2,ob,&(temp->momentumx),&(temp->momentumy),&(temp->momentumz),0x3000);
				 break;
				}
		  }
		else // hit wherever
		  {ob->angle += (rand >> 1);
			Fix(ob->angle);
			ob->momentumx = ob->momentumy = 0;
			ParseMomentum(ob,ob->angle);
		  }


		temp->temp1 = 0x70000;
		NewState(temp,&s_grenade1);
	  }
	break;
  }

 for(tstat=firstactivestat;tstat;tstat=tstat->statnext)
  {
	if (!(tstat->flags & FL_SHOOTABLE))
	  continue;

	dx = abs(tstat->x - ob->x);
	dy = abs(tstat->y - ob->y);
	dz = abs(tstat->z - ob->z);

	if ((dx > 0xc000) || (dy > 0xc000) || (dz > 20))
	 continue;

	magangle = abs(ob->angle - AngleBetween(ob,(objtype*)tstat));
	if (magangle > VANG180)
		 magangle = ANGLES - magangle;

	if (magangle > ANGLES/8)
	  continue;

	DamageThing(tstat,50);


  }

 tilexlow = (int)((ob->x-radius) >>TILESHIFT);
 tileylow = (int)((ob->y-radius) >>TILESHIFT);

 tilexhigh = (int)((ob->x+radius) >>TILESHIFT);
 tileyhigh = (int)((ob->y+radius) >>TILESHIFT);

 for (y=tileylow;y<=tileyhigh;y++)
	for (x=tilexlow;x<=tilexhigh;x++)
		{if ((tilemap[x][y]&0x8000) && (tilemap[x][y]&0x4000))
			{maskedwallobj_t * mw;

			 mw=maskobjlist[tilemap[x][y]&0x3ff];
			 if (mw->flags&MW_SHOOTABLE)
					UpdateMaskedWall(tilemap[x][y]&0x3ff);
			}
		}

}

void AutoTargetHorizon(objtype *ob)
   {
   int dx,dy,angle,mindist,magangle,
       xydist,dz;
   objtype *temp;
   playertype * pstate;

	M_LINKSTATE(ob,pstate);

   mindist = 0x7fffffff;
   for(temp = firstactive;temp;temp=temp->nextactive)
      {
      if (temp == ob)
         continue;
      if ((!(temp->flags & FL_SHOOTABLE)) || (temp->flags & FL_DYING))
         continue;
      if (!CheckLine(ob,temp,SHOOT))
         continue;

      dx = temp->x-ob->x;
      dy = ob->y-temp->y;
      dz = ob->z-temp->z;//-pstate->playerheight+32;

      xydist = FindDistance(dx,dy);
      if (abs(dz<<10)>xydist)
         continue;


      angle = atan2_appx(dx,dy);

      magangle = ob->angle - angle;
      Fix(magangle);

      if (
          (magangle>=(ANGLESDIV8/4)) &&
          (magangle<=(FINEANGLES-(ANGLESDIV8/4)))
         )
         {
         continue;
         }

      if (xydist < mindist)
         {
         mindist = xydist;
         pstate->guntarget=temp;
         temp->flags |= FL_TARGET;
         pstate->targettime=oldpolltime+(VBLCOUNTER);
         }
      }
  }

void  GunAttack (objtype *ob)
{
	playertype * pstate;
	int      damage;

	M_LINKSTATE(ob,pstate);

	MISCVARS->madenoise = true;

 switch (pstate->weapon)
	{
	case wp_pistol:
		SD_PlaySoundRTP(SD_ATKPISTOLSND,ob->x,ob->y);
		damage=DMG_PISTOL;
		break;

	case wp_mp40:
		SD_PlaySoundRTP(SD_ATKMP40SND,ob->x,ob->y);
		damage=DMG_MP40;
		break;

	case wp_twopistol:
		SD_PlaySoundRTP(SD_ATKTWOPISTOLSND,ob->x,ob->y);
		damage=DMG_PISTOL;
		break;
	}

   AutoTargetHorizon(ob);
   RayShoot (ob, damage, (characters[pstate->player].accuracy+gamestate.difficulty)<<3);

}


/*
===============
=
= Cmd_Fire
=
===============
*/
void Cmd_Fire (objtype*ob)
   {
   playertype *pstate;

   M_LINKSTATE(ob,pstate);

//   pstate->buttonheld[bt_attack] = true;

   if (pstate->NETCAPTURED && (!pstate->HASKNIFE))
      return;

   if (W_CHANGE(pstate))
      return;

   pstate->attackframe = 0;

   if ((ob==player) && (pstate->weapon < wp_mp40) && (!pstate->NETCAPTURED))
      gamestate.DODEMOCRATICBONUS1 = false;

   if (!pstate->NETCAPTURED)
      {
      if (pstate->weapon <= wp_mp40)
         NewState(ob,&s_pgunattack1);
 #if (SHAREWARE == 0)
      else if ((pstate->weapon == wp_bat) && (pstate->batblast >= BBTIME))
         {
         pstate->batblast = 0;
         NewState(ob,&s_pbatblast);
         }
      else if (pstate->weapon == wp_dog)
         NewState(ob,&s_serialdogattack);
 #endif
      else
         NewState(ob,&s_pmissattack1);

 #if (SHAREWARE == 0)

      if ((pstate->weapon == wp_dog) && (!ob->momentumz))
         ob->momentumz = -0x50000;
 #endif
      pstate->attackcount = WEAPONS[pstate->weapon].attackinfo[0].mtics;
      pstate->weaponframe = WEAPONS[pstate->weapon].attackinfo[0].frame;
      }

   else if (pstate->NETCAPTURED == 1)
      {
      NewState(player,&s_free);
      pstate->attackcount = FREE.attackinfo[0].mtics;
      pstate->weaponframe = FREE.attackinfo[0].frame;
      }

   }

void PlayNoWaySound ( void )
   {
   if (player->flags & FL_DOGMODE)
      SD_Play(SD_DOGMODEBITE2SND);
   else if ((locplayerstate->player == 1) || (locplayerstate->player == 3))
      SD_Play(SD_PLAYERTBHURTSND);
   else
      SD_Play(SD_NOWAYSND);
   }


/*
===============
=
= Cmd_Use
=
===============
*/

void Cmd_Use (objtype*ob)
{
   int             checkx,checky,doorn,
                  /*newtilex,newtiley,oldtilex,oldtiley,*/elevnum,
                  wallx,wally;
//      statobj_t*      tempsprite=NULL;
   objtype*        tempactor= NULL;
   doorobj_t*      tempdoor=NULL;
   pwallobj_t*      temppwall=NULL;
   wall_t*         tempwall=NULL;
   int             index;
   playertype * pstate;



   M_LINKSTATE(ob,pstate);

#if (SHAREWARE == 0)

   if ((pstate->weapon == wp_dog) && (ob->state != &s_doguse) &&
       (ob->state != &s_dogwait) && (!W_CHANGE(pstate))
      )
      {
      pstate->attackframe = 0;
      NewState(ob,&s_doguse);
      pstate->attackcount = DOGSCRATCH.attackinfo[0].mtics;
      pstate->weaponframe = DOGSCRATCH.attackinfo[0].frame;
      ob->momentumz = -0x40000;
      return;

      }

   else
#endif
     if ((ob->flags & FL_DESIGNATED) && (BATTLEMODE) && (gamestate.battlemode == battle_Tag))
        {
        NewState(ob,&s_tag);
      //return;
        }
//
// find which cardinal direction the player is facing
//
   if (ob->angle < FINEANGLES/8 || ob->angle > 7*FINEANGLES/8)
      {
            checkx = ob->tilex + 1;
            checky = ob->tiley;
            ob->dir = east;
            wallx = (checkx << TILESHIFT);
            wally = (checky << TILESHIFT) + TILEGLOBAL/2;
      }
   else if (ob->angle < 3*FINEANGLES/8)
      {
            checkx = ob->tilex;
            checky = ob->tiley-1;
            ob->dir = north;
            wally = (checky << TILESHIFT) + TILEGLOBAL;
            wallx = (checkx << TILESHIFT) + TILEGLOBAL/2;
      }
   else if (ob->angle < 5*FINEANGLES/8)
      {
            checkx = ob->tilex - 1;
            checky = ob->tiley;
            ob->dir = west;
            wallx = (checkx << TILESHIFT) + TILEGLOBAL;
            wally = (checky << TILESHIFT) + TILEGLOBAL/2;
      }
   else
      {
            checkx = ob->tilex;
            checky = ob->tiley + 1;
            ob->dir = south;
            wally = (checky << TILESHIFT);
            wallx = (checkx << TILESHIFT) + TILEGLOBAL/2;
      }


   if (actorat[checkx][checky])
      {
      tempdoor=(doorobj_t*)actorat[checkx][checky];
      tempactor = (objtype*)actorat[checkx][checky];
      tempwall = (wall_t*)actorat[checkx][checky];
      }
   doorn = tilemap[checkx][checky] & ~0x2000;
//      if (sprites[checkx][checky])
//       tempsprite = sprites[checkx][checky];
   if (doorn == (elevatorstart + 6))
      return;

   if (pstate->buttonheld[bt_use])
      return;

   if (doorn == (elevatorstart + 1))
      {
      tilemap[checkx][checky]++;              // flip switch
      if (MAPSPOT(ob->tilex,ob->tiley,1) == ALTELEVATORTILE);
         // playstate = ex_secretlevel;
      else if (ob==player)
         playstate = ex_completed;
      }


   else if (doorn == (elevatorstart + 5))

      {
      elevnum = MAPSPOT(ob->tilex,ob->tiley,1) - 90;
      tempwall->flags |= FL_S_FLIPPED;
      OperateElevatorSwitch(ob,elevnum,checkx,checky);
      }
   else if (tempdoor && tempdoor->which==PWALL)
      {
      temppwall=(pwallobj_t *)tempdoor;
      OperatePushWall (temppwall->num,ob->dir, ob == player );
      }
   else if ((doorn&0x8000) && (!(doorn&0x4000)))
      {
      doorobj_t* dptr = doorobjlist[doorn&0x3ff];
      int dnum = doorn&0x3ff;
      int lock;

      OperateDoor (pstate->keys, dnum, (ob == player));
      if (dptr->eindex != -1)
         {
         elevator_t*eptr;


         lock = dptr->lock;
         if ( lock && !( pstate->keys & ( 1 << ( lock - 1 ) ) ) )
            {
            if (ob==player)
               {
               // locked
               switch (lock)
                  {
                  case 1:
                     AddMessage("You need the \\EGOLD key",MSG_DOOR);
                     break;

                  case 2:
                     AddMessage("You need the \\FSILVER key",MSG_DOOR);
                     break;

                  case 3:
                     AddMessage("You need the \\8IRON key",MSG_DOOR);
                     break;

                  case 4:
                     AddMessage("You need the \\AOSCURO key",MSG_DOOR);
                     break;

                  default:
                     AddMessage("This door appears to be locked",MSG_DOOR);
                     break;
                  }

               SD_Play( SD_NOITEMSND );
               }
            return;
            }

         eptr = &ELEVATOR[dptr->eindex];
         if (((dnum == eptr->door1) && (eptr->state == ev_rad)) ||
             ((dnum == eptr->door2) && (eptr->state == ev_ras))
            )
            if (ob == player)
               AddMessage("Elevator is on the way.",MSG_GAME);

         OperateElevatorDoor(dnum);
         }

      }

   else if ((tempactor) && (tempactor->which == ACTOR) &&
            (tempactor->obclass == pillarobj) &&
            DISTOK(ob->x,tempactor->x,TD) &&
            DISTOK(ob->y,tempactor->y,TD) &&
            (!(tempactor->flags & FL_DONE)) &&
            (!MAPSPOT(tempactor->tilex,tempactor->tiley,2))
           )

      {if ((tempactor->dir == nodir) ||
           (tempactor->dir == ob->dir))
            {if (tempactor->dir == nodir)
                {
                tempactor->dir = ob->dir;
                ParseMomentum(tempactor,dirangle8[tempactor->dir]);
                }
             SD_PlaySoundRTP ( SD_PUSHWALLSND, tempactor->x, tempactor->y );
             tempactor->flags |= FL_ACTIVE;
             tempactor->flags |= FL_FLIPPED;
//               MakeActive(tempactor);
             tempactor->whatever = ob;
             gamestate.secretcount++;
            }

      }
   else if ((tempwall) && (tempwall->which == WALL) &&
            (tempwall->flags & FL_SWITCH) )
      {
      tempwall->flags |= FL_S_FLIPPED;
      if ((tempwall->flags & FL_W_INVERTED) &&
            DISTOK(ob->x,wallx,TD) &&
            DISTOK(ob->y,wally,TD) &&
            DISTOK(ob->z,0,32)
         )
         {
         index = touchindices[checkx][checky]-1;
         if (!(tempwall->flags & FL_ON))
            {
            maskobjlist[tilemap[checkx][checky]&0x3ff]->toptexture++;
            tempwall->flags |= FL_ON;
            TRIGGER[index] = 1;
            SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
            if (ob==player)
               AddMessage("Switch turned on.",MSG_GAME);
            }
         else if (tempwall->flags & FL_REVERSIBLE)
            {
            maskobjlist[tilemap[checkx][checky]&0x3ff]->toptexture--;
            tempwall->flags &= ~FL_ON;
            TRIGGER[index] = 1;
            SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
            if (ob==player)
               AddMessage("Switch turned off.",MSG_GAME);
            }

         }
      else if (DISTOK(ob->x,wallx,TD) &&
               DISTOK(ob->y,wally,TD) &&
               !(tempwall->flags & FL_W_INVERTED)
              )
         {
         index = touchindices[checkx][checky]-1;
         if (!(tempwall->flags & FL_ON))
            {
            tilemap[checkx][checky]++;
            tempwall->flags |= FL_ON;
            TRIGGER[index] = 1;
            SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
            if (ob==player)
               AddMessage("Switch turned on.",MSG_GAME);
            }
         else if (tempwall->flags & FL_REVERSIBLE)
            {
            tilemap[checkx][checky]--;
            tempwall->flags &= ~FL_ON;
            TRIGGER[index] = 1;
            SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
            if (ob==player)
               AddMessage("Switch turned off.",MSG_GAME);
            }

         }
      }
   else if ((tempwall) && (tempwall->which == WALL) && (ob==player))
      PlayNoWaySound();
//      else
//         SD_PlaySoundRTP (SD_NOWAYSND,ob->x,ob->y);
//   pstate->buttonheld[bt_use] = true;
}


/*
=============================================================================

						  USER CONTROL

=============================================================================
*/


//******************************************************************************
//
// PollKeyboardButtons
//
//******************************************************************************

void PollKeyboardButtons (void)
{
   int i;

   QueueLetterInput ();
   IN_UpdateKeyboard();

   for (i = 0; i < NUMBUTTONS; i++)
      if (Keystate[buttonscan[i]])
         buttonpoll[i] = true;
}

//******************************************************************************
//
// PollMouseButtons
//
//******************************************************************************

void PollMouseButtons (void)
   {
   int i;
   int buttons;
   int mask;
   int press;

   buttons = IN_GetMouseButtons();

   mask = 1;
   for( i = 0; i < 3; i++, mask <<= 1 )
      {
      press = buttons & mask;

      if ( press )
         {
//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
//            ( DoubleClickCount[ i ] != 2 ) )
         if ( buttonmouse[ i ] != bt_nobutton )
            {
            buttonpoll[ buttonmouse[ i ] ] = true;
            }
         }

      // Check double-click
      if ( buttonmouse[ i + 3 ] != bt_nobutton )
         {
         if ( press )
            {
            // Was the button pressed last tic?
            if ( !DoubleClickPressed[ i ] )
               {
               // Yes, take note of it
               DoubleClickPressed[ i ] = true;

               // Is this the first click, or a really late click?
               if ( ( DoubleClickCount[ i ] == 0 ) ||
                  ( ticcount >= DoubleClickTimer[ i ] ) )
                  {
                  // Yes, now wait for a second click
                  DoubleClickTimer[ i ] = ticcount + DoubleClickSpeed;

                     //( tics << 5 );
                  DoubleClickCount[ i ] = 1;
                  }
               else
                  {
                  // Second click
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  DoubleClickTimer[ i ] = 0;
                  DoubleClickCount[ i ] = 2;
                  }
               }
            else
               {
               // After second click, button remains pressed
               // until user releases it
               if ( DoubleClickCount[ i ] == 2 )
                  {
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  }
               }
            }
         else
            {
            if ( DoubleClickCount[ i ] == 2 )
               {
               DoubleClickCount[ i ] = 0;
               }
            DoubleClickPressed[ i ] = false;
            }
         }
      }
   }


//******************************************************************************
//
// PollJoystickButtons
//
//******************************************************************************
void PollJoystickButtons
   (
   void
   )

   {
   int i;
   int buttons;
   int mask;
   int num;
   int press;

   buttons = IN_JoyButtons ();

   if ( joypadenabled )
      {
      num = 4;
      mask = 1;
      }
   else
      {
      num = 2;
      if ( joystickport )
         {
         mask = 4;
         }
      else
         {
         mask = 1;
         }
      }

   for( i = 0; i < num; i++, mask <<= 1 )
      {
      press = buttons & mask;

      if ( press )
         {
//         if ( ( buttonjoy[ i ] != bt_nobutton ) &&
//            ( JoyDblClickCount[ i ] != 2 ) )
         if ( buttonjoy[ i ] != bt_nobutton )
            {
            buttonpoll[ buttonjoy[ i ] ] = true;
            }
         }

      // Check double-click
      if ( buttonjoy[ i + 4 ] != bt_nobutton )
         {
         if ( press )
            {
            // Was the button pressed last tic?
            if ( !JoyDblClickPressed[ i ] )
               {
               // Yes, take note of it
               JoyDblClickPressed[ i ] = true;

               // Is this the first click, or a really late click?
               if ( ( JoyDblClickCount[ i ] == 0 ) ||
                  ( ticcount >= JoyDblClickTimer[ i ] ) )
                  {
                  // Yes, now wait for a second click
                  JoyDblClickTimer[ i ] = ticcount + DoubleClickSpeed;

                     //( tics << 5 );
                  JoyDblClickCount[ i ] = 1;
                  }
               else
                  {
                  // Second click
                  buttonpoll[ buttonjoy[ i + 4 ] ] = true;
                  JoyDblClickTimer[ i ] = 0;
                  JoyDblClickCount[ i ] = 2;
                  }
               }
            else
               {
               // After second click, button remains pressed
               // until user releases it
               if ( JoyDblClickCount[ i ] == 2 )
                  {
                  buttonpoll[ buttonjoy[ i + 4 ] ] = true;
                  }
               }
            }
         else
            {
            if ( JoyDblClickCount[ i ] == 2 )
               {
               JoyDblClickCount[ i ] = 0;
               }
            JoyDblClickPressed[ i ] = false;
            }
         }
      }
   }


//===========================================================================

//******************************************************************************
//
// PollKeyboardMove
//
//******************************************************************************

void PollKeyboardMove
   (
   void
   )

   {
   if ( ( buttonpoll[ bt_turnaround ] ) && ( turnaround == 0 ) )
      {
      turnaround = 1;
      turnaroundtime = 15 + tics;
      turnheldtime = 0;
      }
   if ( turnaround == 0 )
      {
      if ( buttonpoll[ di_east ] )
         {
         turnheldtime+=tics;
         if (turnheldtime>=TURBOTURNTIME)
            {
            KX = -KEYBOARDNORMALTURNAMOUNT;
            }
         else
            {
            KX = -KEYBOARDPREAMBLETURNAMOUNT;
            }
         }
      else if ( buttonpoll[ di_west ] )
         {
         turnheldtime+=tics;
         if (turnheldtime>=TURBOTURNTIME)
            {
            KX = KEYBOARDNORMALTURNAMOUNT;
            }
         else
            {
            KX = KEYBOARDPREAMBLETURNAMOUNT;
            }
         }
      else
         {
		   KX = 0;
         turnheldtime=0;
         }
      if ( (buttonpoll[bt_run]) &&
           ( (turnheldtime>=TURBOTURNTIME) || (turnheldtime==0) )
         )
         KX = FixedMul(KX,TURBOTURNAMOUNT);
      }
   else
      {
      KX=TURNAROUNDSPEED;
      turnaroundtime-=tics;
      if (turnaroundtime<=0)
         {
         turnaround=0;
         KX=((turnaroundtime*TURNAROUNDSPEED)>>1);
         }
      }

   if ( buttonpoll[ di_north ] )
      {
      KY = -BASEMOVE;
      }
   else if ( buttonpoll[ di_south ] )
      {
      KY = BASEMOVE;
      }
   else
      KY = 0;

   if (buttonpoll[bt_run])
      {
      KY <<= 1;
      }
}

//******************************************************************************
//
// PollMouseMove
//
//******************************************************************************

//#define MOUSE_RY_SHIFT 12
//#define MOUSE_TZ_SHIFT 3
#define MOUSE_TZ_SENSITIVITY_SCALE 65535
#define MOUSE_RY_SENSITIVITY_SCALE 18725
//#define MOUSE_RY_INPUT_SCALE 6000
#define MOUSE_TZ_INPUT_SCALE 20
int mouse_ry_input_scale = 5000;

int sensitivity_scalar[15] =
    {
    0,1,2,3,4,5,6,8,11,13,15,18,12,13,14
    };

//#define MOUSE_RY_SCALE 65535

//#define MOUSE_TZ_SCALE 65535
#define MAXMOUSETURN 7000000

void PollMouseMove (void)
{
   union REGS inregs;
   union REGS outregs;
   short int  mousexmove,
              mouseymove;

   inregs.x.eax = MDelta;
   int386 (0x33, &inregs, &outregs);

   mousexmove = outregs.w.cx;
	mouseymove = outregs.w.dx;

   if (abs(mousexmove)>abs(mouseymove))
      mouseymove/=2;
   else
      mousexmove/=2;
   MX = 0;
   MY = 0;


   if ((abs (mouseymove)) >= threshold)
      {
      MY =  MOUSE_TZ_INPUT_SCALE*mouseymove;

     // MY += FixedMul(MY,mouseadjustment*MOUSE_TZ_SENSITIVITY_SCALE);
      if (abs(mouseymove)>200)
         {
         buttonpoll[bt_run]=true;
         }
      }

   if ((abs (mousexmove)) >= threshold)
      {
      //MX = -MOUSE_RY_INPUT_SCALE*mousexmove;
      MX = -mouse_ry_input_scale*mousexmove;
      MX += FixedMul(MX,sensitivity_scalar[mouseadjustment]*MOUSE_RY_SENSITIVITY_SCALE);
   //   if (abs(MX) > MAXMOUSETURN)
     //   MX = MAXMOUSETURN*SGN(MX);
      if (abs(mouseymove)>10)
         {
         buttonpoll[bt_run]=true;
         }
      }

//   if (MY > 0)
//      MX -= (MX/2);

}


//******************************************************************************
//
// PollJoystickMove
//
//******************************************************************************

void PollJoystickMove (void)
{
   int   joyx,joyy;

   INL_GetJoyDelta (joystickport, &joyx, &joyy);
   if ( joypadenabled )
      {
      if (joyx >= threshold)
         {
         buttonpoll[ di_east ] = true;
         }
      if (-joyx >= threshold)
         {
         buttonpoll[ di_west ] = true;
         }
      if ( joyy >= threshold )
         {
         buttonpoll[ di_south ] = true;
         }
      if ( -joyy >= threshold )
         {
         buttonpoll[ di_north ] = true;
         }
      }
   else
      {
      if ((abs (joyx)) >= threshold)
         {
         JX = ((-joyx)<<13)+((-joyx)<<11);
         turnheldtime += tics;
         }
      else
         JX = 0;

      if ((abs (joyy)) >= threshold)
         {
         JY = joyy<<4;
         }
      else
         JY = 0;
      if (buttonpoll[bt_run])
         {
         JX <<= 1;
         JY <<= 1;
         }
      }
   }

//******************************************************************************
//
// StartVRFeedback
//
//******************************************************************************

void StartVRFeedback (int guntype)
{
   union REGS inregs;
   union REGS outregs;

   inregs.x.eax = VR_FEEDBACK_SERVICE;
   inregs.x.ebx = 1;
   inregs.x.ecx = guntype;
   int386 (0x33, &inregs, &outregs);
}

//******************************************************************************
//
// StopVRFeedback
//
//******************************************************************************

void StopVRFeedback (void)
{
   union REGS inregs;
   union REGS outregs;

   inregs.x.eax = VR_FEEDBACK_SERVICE;
   inregs.x.ebx = 0;
   int386 (0x33, &inregs, &outregs);
}

//******************************************************************************
//
// PollVirtualReality
//
//******************************************************************************

#define VR_BUTTON(x) ((vr_buttons>>x) & 1)

void PollVirtualReality (void)
{
   union REGS inregs;
   union REGS outregs;
   short int  mousexmove,
              mouseymove;
   word vr_buttons;

   inregs.x.eax = VR_INPUT_SERVICE;

   inregs.x.ebx = player->angle;
   inregs.x.ecx = player->yzangle;

   int386 (0x33, &inregs, &outregs);

   vr_buttons = outregs.w.bx;

   buttonpoll[bt_run          ] |= VR_BUTTON(VR_RUNBUTTON          );
   buttonpoll[bt_strafeleft   ] |= VR_BUTTON(VR_STRAFELEFTBUTTON   );
   buttonpoll[bt_straferight  ] |= VR_BUTTON(VR_STRAFERIGHTBUTTON  );
   buttonpoll[bt_attack       ] |= VR_BUTTON(VR_ATTACKBUTTON       );
   buttonpoll[bt_lookup       ] |= VR_BUTTON(VR_LOOKUPBUTTON       );
   buttonpoll[bt_lookdown     ] |= VR_BUTTON(VR_LOOKDOWNBUTTON     );
   buttonpoll[bt_swapweapon   ] |= VR_BUTTON(VR_SWAPWEAPONBUTTON   );
   buttonpoll[bt_use          ] |= VR_BUTTON(VR_USEBUTTON          );
   buttonpoll[bt_horizonup    ] |= VR_BUTTON(VR_HORIZONUPBUTTON    );
   buttonpoll[bt_horizondown  ] |= VR_BUTTON(VR_HORIZONDOWNBUTTON  );
   buttonpoll[bt_map          ] |= VR_BUTTON(VR_MAPBUTTON          );
   buttonpoll[bt_pistol       ] |= VR_BUTTON(VR_PISTOLBUTTON       );
   buttonpoll[bt_dualpistol   ] |= VR_BUTTON(VR_DUALPISTOLBUTTON   );
   buttonpoll[bt_mp40         ] |= VR_BUTTON(VR_MP40BUTTON         );
   buttonpoll[bt_missileweapon] |= VR_BUTTON(VR_MISSILEWEAPONBUTTON);
   buttonpoll[bt_recordsound  ] |= VR_BUTTON(VR_RECORDBUTTON       );

   mousexmove = outregs.w.cx;
	mouseymove = outregs.w.dx;

   VX = 0;
   VY = 0;


   if ((abs (mouseymove)) >= threshold)
      {
      VY =  MOUSE_TZ_INPUT_SCALE*mouseymove;
      if (abs(mouseymove)>200)
         {
         buttonpoll[bt_run]=true;
         }
      }

   if ((abs (mousexmove)) >= threshold)
      {
      VX = -mouse_ry_input_scale*mousexmove;
      VX += FixedMul(MX,sensitivity_scalar[mouseadjustment]*MOUSE_RY_SENSITIVITY_SCALE);
      if (abs(mousexmove)>10)
         {
         buttonpoll[bt_run]=true;
         }
      }
}


int scaleamt[16] = {0x10000,  0x10000,  0x10000,  0x20000,  0x12000,
						 0x14000,  0x14000, 0x16000, 0x16000, 0x18000,
						 0x18000, 0x18000, 0x18000};


//******************************************************************************
//
// PollMove ()
//
//******************************************************************************

boolean aimbuttonpressed=false;
void PollMove (void)
{
	int angle;
   int x, y;


   x = KX + MX + JX + CX + VX;
   y = KY + MY + JY + CY + VY;

   if (buttonpoll[bt_aimbutton])
      {
      if (y>0)
         {
         buttonpoll[bt_horizonup]=1;
         y=0;
         aimbuttonpressed=true;
         }
      else if (y<0)
         {
         buttonpoll[bt_horizondown]=1;
         y=0;
         aimbuttonpressed=true;
         }
      else if (aimbuttonpressed==false)
         {
         buttonpoll[bt_lookup]=1;
         buttonpoll[bt_lookdown]=1;
         }
      }
   else
      {
      aimbuttonpressed=false;
      }

   if (player->flags & FL_FLEET)
		y += y>>1;

   if ((locplayerstate->NETCAPTURED == 1) && (!locplayerstate->HASKNIFE))
   {
      if (first)
      {
         nettics = ticcount + (VBLCOUNTER * 4);
         first = 0;
      }

      if (x > 0)
         {
         rightmom += NETMOM;
         if (lastmom!=0)
            controlbuf[2]=x<<1;
         lastmom=0;
         }
      else
         if (x < 0)
            {
            leftmom += NETMOM;
            if (lastmom!=1)
               controlbuf[2]=x<<1;
            lastmom=1;
            }
         else
         {
            rightmom -= (NETMOM >> 2);
            if (rightmom < 0)
               rightmom = 0;
            leftmom  -= (NETMOM >> 2);
            if (leftmom < 0)
               leftmom = 0;
         }

      if ((ticcount > nettics) && (rightmom > (NETMOM * 2)) &&
                                  (leftmom > (NETMOM * 2)))
      {
         rightmom = 0;
         leftmom  = 0;
         first    = 1;
         lastmom^=1;
			locplayerstate->NETCAPTURED = 0;
			MISCVARS->NET_IN_FLIGHT = false;
         NewState(player, &s_player);
			locplayerstate->weaponuptics = WEAPONS[locplayerstate->weapon].screenheight/GMOVE;
			locplayerstate->weaponheight = locplayerstate->weaponuptics*GMOVE ;
      }
   }
   else if ((buttonpoll[bt_strafe]) && (turnaround==0))
   {
      // strafing
      if (x < 0)
         {
			angle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);

         x = (x>>10) + (x >> 11);

         controlbuf[0] = -(FixedMul (x, costable[angle]));
         controlbuf[1] = FixedMul (x, sintable[angle]);
			}
      else if (x > 0)
			{
         angle = (player->angle + FINEANGLES/4)&(FINEANGLES-1);

         x = (x>>10) + (x >> 11);

			controlbuf[0] = FixedMul (x, costable[angle]);
         controlbuf[1] = -(FixedMul (x, sintable[angle]));
         }
      if (y != 0)
         {
         controlbuf[0] += -(FixedMul (y, viewcos));
         controlbuf[1] += (FixedMul (y, viewsin));
         }
   }
   else
   {
      if (y != 0)
         {
         controlbuf[0] = -FixedMul (y, viewcos);
         controlbuf[1] = FixedMul (y, viewsin);
         }

      if (x != 0)
         controlbuf[2] = x;
   }

   if (buttonpoll[bt_strafeleft])
      {
      angle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);
      controlbuf[0] += -(FixedMul (STRAFEAMOUNT, costable[angle]));
      controlbuf[1] +=   FixedMul (STRAFEAMOUNT, sintable[angle]);
		}
   else if (buttonpoll[bt_straferight])
      {
      angle = (player->angle + FINEANGLES/4)&(FINEANGLES-1);
      controlbuf[0] += -(FixedMul (STRAFEAMOUNT, costable[angle]));
      controlbuf[1] +=   FixedMul (STRAFEAMOUNT, sintable[angle]);
      }
}


//******************************************************************************
//
// PollCyberman ()
//
//******************************************************************************

void PollCyberman (void)
{
   int i;
   int mask;
   int press;

   SWIFT_Get3DStatus (&SWIFTStatus);

   mask = 4;
   for( i = 0; i < 3; i++, mask >>= 1 )
      {
      press = SWIFTStatus.buttons & mask;

      if ( press )
         {
//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
//            ( DoubleClickCount[ i ] != 2 ) )
         if ( buttonmouse[ i ] != bt_nobutton )
            {
            buttonpoll[ buttonmouse[ i ] ] = true;
            }
         }

      // Check double-click
      if ( buttonmouse[ i + 3 ] != bt_nobutton )
         {
         if ( press )
            {
            // Was the button pressed last tic?
            if ( !DoubleClickPressed[ i ] )
               {
               // Yes, take note of it
               DoubleClickPressed[ i ] = true;

               // Is this the first click, or a really late click?
               if ( ( DoubleClickCount[ i ] == 0 ) ||
                  ( ticcount >= DoubleClickTimer[ i ] ) )
                  {
                  // Yes, now wait for a second click
                  DoubleClickTimer[ i ] = ticcount + DoubleClickSpeed;

                     //( tics << 5 );
                  DoubleClickCount[ i ] = 1;
                  }
               else
                  {
                  // Second click
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  DoubleClickTimer[ i ] = 0;
                  DoubleClickCount[ i ] = 2;
                  }
               }
            else
               {
               // After second click, button remains pressed
               // until user releases it
               if ( DoubleClickCount[ i ] == 2 )
                  {
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  }
               }
            }
         else
            {
            if ( DoubleClickCount[ i ] == 2 )
               {
               DoubleClickCount[ i ] = 0;
               }
            DoubleClickPressed[ i ] = false;
            }
         }
      }

   if (SWIFTStatus.pitch > 0)
     CYBERLOOKUP = true;
   else if (SWIFTStatus.pitch < 0)
     CYBERLOOKDOWN = true;

   if ((abs (SWIFTStatus.x)) > CYBERDEADRANGE)
   {
      CX = -(SGN (SWIFTStatus.x) * (( (abs(SWIFTStatus.x)-CYBERDEADRANGE) ) << 10));
      turnheldtime += tics;
   }
   else
      if (SWIFTStatus.x != oldcyberx)
		{
         turnheldtime += tics;
         if (SWIFTStatus.x > oldcyberx)
				CX = -(0xB8000);
         else
				CX = 0xB8000;

         oldcyberx = SWIFTStatus.x;
      }
      else
         CX = 0;

   if ((abs (SWIFTStatus.y)) > CYBERDEADRANGE)
   {
      CY = SWIFTStatus.y >> 2;
   }
	else
      CY = 0;
}

//******************************************************************************
//
// PollAssassin ()
//
//******************************************************************************

#define MAXRAMPS 5
typedef struct
   {
   int  min;
   int  factor;
   } RampType;
void PollAssassin (void)
{
   int i;
   int mask;
   int press;
   int yaw;
   int strafeAngle;
   int acc;
   int numramps=4;
   RampType ramp[MAXRAMPS]={
                              {0,280000},
                              {4,380000},
                              {10,480000},
                              {25,680000},
//                              {25,( (1<<26)/80  )}
                            };

   SWIFT_Get3DStatus (&SWIFTStatus);

   mask = 4;
   for( i = 0; i < 3; i++, mask >>= 1 )
      {
      press = SWIFTStatus.buttons & mask;

      if ( press )
         {
//         if ( ( buttonmouse[ i ] != bt_nobutton ) &&
//            ( DoubleClickCount[ i ] != 2 ) )
         if ( buttonmouse[ i ] != bt_nobutton )
            {
            buttonpoll[ buttonmouse[ i ] ] = true;
            }
         }

      // Check double-click
      if ( buttonmouse[ i + 3 ] != bt_nobutton )
         {
         if ( press )
            {
            // Was the button pressed last tic?
            if ( !DoubleClickPressed[ i ] )
               {
               // Yes, take note of it
               DoubleClickPressed[ i ] = true;

               // Is this the first click, or a really late click?
               if ( ( DoubleClickCount[ i ] == 0 ) ||
                  ( ticcount >= DoubleClickTimer[ i ] ) )
                  {
                  // Yes, now wait for a second click
                  DoubleClickTimer[ i ] = ticcount + DoubleClickSpeed;

                     //( tics << 5 );
                  DoubleClickCount[ i ] = 1;
                  }
               else
                  {
                  // Second click
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  DoubleClickTimer[ i ] = 0;
                  DoubleClickCount[ i ] = 2;
                  }
               }
            else
               {
               // After second click, button remains pressed
               // until user releases it
               if ( DoubleClickCount[ i ] == 2 )
                  {
                  buttonpoll[ buttonmouse[ i + 3 ] ] = true;
                  }
               }
            }
         else
            {
            if ( DoubleClickCount[ i ] == 2 )
               {
               DoubleClickCount[ i ] = 0;
               }
            DoubleClickPressed[ i ] = false;
            }
         }
      }

   buttonpoll[bt_horizonup] |=   ((SWIFTStatus.buttons>>7) & 1);
   buttonpoll[bt_horizondown] |= ((SWIFTStatus.buttons>>8) & 1);

   if ( abs(SWIFTStatus.pitch) < (20<<6) )
      {
      SWIFTStatus.pitch = 0;
      }
   else
      {
      SWIFTStatus.pitch -= SGN(SWIFTStatus.pitch)*(20<<6);
      }

   if ( abs(SWIFTStatus.pitch) > (60<<6) )
      {
      buttonpoll[bt_run] = 1;
      }

   if ( abs(SWIFTStatus.roll) > (80<<6) )
      {
      buttonpoll[bt_run] = 1;
      }


   if ( abs(SWIFTStatus.roll) < (20<<6) )
      {
      SWIFTStatus.roll = 0;
      }
   else
      {
      SWIFTStatus.roll -= SGN(SWIFTStatus.roll)*(20<<6);
      }

   strafeAngle = (player->angle - FINEANGLES/4)&(FINEANGLES-1);

   controlbuf[0] += -(FixedMulShift (SWIFTStatus.pitch, viewcos,16))+
                   FixedMulShift (-SWIFTStatus.roll, costable[strafeAngle], 16);

   controlbuf[1] +=  FixedMulShift (SWIFTStatus.pitch, viewsin,16) -
                   FixedMulShift (-SWIFTStatus.roll, sintable[strafeAngle], 16);

   yaw = abs(SWIFTStatus.yaw);
   acc = 0;
   for (i=0;i<numramps;i++)
      {
      if (yaw > ramp[i].min)
         {
         if (i>0)
            {
            acc += ramp[i].min*(ramp[i].factor-ramp[i-1].factor);
            }
         }
      else
         {
         i++;
         break;
         }
      }
   controlbuf[2]= SWIFTStatus.yaw * ramp[i-1].factor - acc;
}


//******************************************************************************
//
// PollControls
//
// Gets user or demo input, call once each frame
//
// controlx     set between -100 and 100 per tic
// controly
//
//******************************************************************************


void PollControls (void)
{
   int   i;

   if (standalone==true)
      return;

   lastpolltime=controlupdatetime;

   memset (buttonpoll, 0, sizeof(buttonpoll));

   controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
   CYBERLOOKUP = CYBERLOOKDOWN = false;

   if (gamestate.autorun==1)
	   buttonpoll[bt_run] = true;


//
// get button states
//
   PollKeyboardButtons ();

   if (mouseenabled && !cybermanenabled)
      PollMouseButtons ();

	if (joystickenabled)
      PollJoystickButtons ();


//
// get movements
//
   if (joystickenabled)
      PollJoystickMove ();

	if (cybermanenabled)
      PollCyberman ();

   else if (mouseenabled && MousePresent)
      PollMouseMove ();

   PollKeyboardMove ();

   if (vrenabled)
      PollVirtualReality ();

   PollMove ();

   if (spaceballenabled)
      PollSpaceBall ();

   else if (assassinenabled)
       PollAssassin ();


	buttonbits = 0;
	if (player->flags & FL_DYING) // Player has died
      {
      if ((playerdead==true) &&
          ( buttonpoll[ bt_strafe ] ||
            buttonpoll[ bt_attack ] ||
            buttonpoll[ bt_use ] ||
            ((gamestate.battlemode == battle_Hunter) &&
             (BATTLE_Team[player->dirchoosetime] == BATTLE_It)
            )
          )
         )
         {
         AddRespawnCommand();
         }
      memset (buttonpoll, 0, sizeof(buttonpoll));
      controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
      }

   if ((PausePressed==true) && (modemgame==false))
      {
      PausePressed=false;
      if (GamePaused==true)
         AddPauseStateCommand(COM_UNPAUSE);
      else
         {
         AddPauseStateCommand(COM_PAUSE);
         }
      }
	if (Keyboard[sc_Insert] && Keyboard[sc_X])
      AddExitCommand();

   for (i = (NUMTXBUTTONS-1); i >= 0; i--)
      {
      buttonbits <<= 1;
		if (buttonpoll[i])
         buttonbits |= 1;
		}

   UpdateClientControls();
}


void ResetWeapons(objtype *ob)
{playertype *pstate;

 M_LINKSTATE(ob,pstate);

 pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
 pstate->new_weapon = pstate->oldweapon;
 pstate->missileweapon = pstate->oldmissileweapon;
 ob->shapeoffset = pstate->oldshapeoffset;
 pstate->attackframe = pstate->weaponframe = 0;

 if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
	DrawBarAmmo (false);
}




void SaveWeapons(objtype*ob)
{playertype *pstate;

 if ((ob->flags&FL_DOGMODE) || (ob->flags&FL_GODMODE))
    return;

 //pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
 M_LINKSTATE(ob,pstate);

 pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
 pstate->oldweapon = pstate->new_weapon;
 pstate->oldmissileweapon = pstate->missileweapon;
 pstate->oldshapeoffset = ob->shapeoffset;

}

/*
void SaveWeapons(objtype*ob)
{playertype *pstate;

 if ((ob->flags&FL_DOGMODE) || (ob->flags&FL_GODMODE))
    return;

 //pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
 M_LINKSTATE(ob,pstate);

 pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
 pstate->oldweapon = pstate->weapon;
 pstate->oldmissileweapon = pstate->missileweapon;
 pstate->oldshapeoffset = ob->shapeoffset;

}
*/


#define GiveProtection(flag,time,sound)                  \
   {                                                     \
   if ((ob->flags & flag) || (ob->flags & FL_GODMODE) || \
       (ob->flags & FL_DOGMODE))                         \
      return;                                            \
   ob->flags &= ~(FL_BPV|FL_GASMASK|FL_AV);              \
   ob->flags |= flag;                                    \
   SD_PlaySoundRTP(sound,ob->x, ob->y);                  \
   pstate->protectiontime = time;                        \
   gamestate.supercount ++;                              \
   }




boolean GivePowerup(objtype *ob,int flag,int time,int sound)
   {
   playertype *pstate;


   if ((ob->flags & flag) ||
       (ob->flags & FL_GODMODE) ||
       (ob->flags & FL_DOGMODE)
      )
      return false;


   M_LINKSTATE(ob,pstate);

   /*
   if (ob->flags & FL_DOGMODE)
      {
      ob->temp2 = DOGMODERISE;
      ResetWeapons(ob);
      if (ob->state->condition & SF_DOGSTATE)
         NewState(ob,&s_player);
      }
   else if (ob->flags & FL_GODMODE)
      {
      ob->temp2 = GODMODEFALL;
      ResetWeapons(ob);
      }
   */
   ob->flags &= ~(FL_SHROOMS|FL_FLEET|FL_ELASTO|FL_GODMODE|FL_DOGMODE);
   ob->flags |= flag;
   pstate->poweruptime = time;
   pstate->soundtime = 0;
   SD_PlaySoundRTP(sound,ob->x, ob->y);
   gamestate.supercount ++;
   return true;

   }



void GiveLifePoints(objtype *ob,int points)
   {
   SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);

   UpdateTriads (ob,points);
   if (ob==player)
      DrawTriads (false);

   }


boolean GiveBulletWeapon(objtype *ob,int bulletweapon,statobj_t*check)
   {
   playertype *pstate;

   M_LINKSTATE(ob,pstate);

   if ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
      return false;

   if (!ARMED(ob->dirchoosetime))
      return false;

   if (pstate->HASBULLETWEAPON[bulletweapon])
      return false;

   GiveWeapon(ob,bulletweapon);
   if ( gamestate.BattleOptions.WeaponPersistence )
      {
      LASTSTAT->z = check->z;
      }
   SD_PlaySoundRTP(SD_GETWEAPONSND,ob->x, ob->y);
   return true;

   }


boolean GivePlayerMissileWeapon(objtype *ob, playertype *pstate,
                                statobj_t *check)
   {
   if  ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
      return false;


   if (!ARMED(ob->dirchoosetime))
      return false;

   if ((GetWeaponForItem(check->itemnumber) == pstate->missileweapon) &&
       (check->ammo == stats[check->itemnumber].ammo) &&
       (pstate->ammo == stats[check->itemnumber].ammo)
      )
      return false;

   SD_PlaySoundRTP(SD_GETWEAPONSND,ob->x, ob->y);
   GiveMissileWeapon(ob,GetWeaponForItem(check->itemnumber));
   if (gamestate.BattleOptions.WeaponPersistence)
         LASTSTAT->z = check->z;

   gamestate.missilecount ++;

   if (BATTLEMODE && (gamestate.BattleOptions.Ammo != bo_normal_shots))
      {if (gamestate.BattleOptions.Ammo == bo_one_shot)
         pstate->ammo = 1;
      else
         pstate->ammo = -1;
      }
   else
      pstate->ammo = check->ammo;
   if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
      DrawBarAmmo (false);

   return true;

   }


#define LocalBonusMessage(string)  \
   {                               \
   if (ob == player)               \
     AddMessage(string,MSG_BONUS); \
   }
#define LocalBonus1Message(string)  \
   {                               \
   if (ob == player)               \
     AddMessage(string,MSG_BONUS1); \
   }


/*
=================================
=
=   GetBonusTimeForItem
=
=================================
*/

int GetBonusTimeForItem(int itemnumber)
   {
   specials *which;

   if ( BATTLEMODE )
      {
      which = &gamestate.SpecialsTimes;
      }
   else
      {
      which = &CurrentSpecialsTimes;
      }

   switch(itemnumber)
      {
      case stat_godmode:
         return which->GodModeTime;

      case stat_dogmode:
         return which->DogModeTime;

      case stat_mushroom:
         return which->ShroomsModeTime;

      case stat_elastic:
         return which->ElastoModeTime;

      case stat_asbesto:
         return which->AsbestosVestTime;

      case stat_bulletproof:
         return which->BulletProofVestTime;

      case stat_gasmask:
         return which->GasMaskTime;

      case stat_fleetfeet:
         return which->MercuryModeTime;
      }

   return -1;

   }




/*
=================================
=
=   GetRespawnTimeForItem
=
=================================
*/



int GetRespawnTimeForItem(int itemnumber)
   {
   switch(itemnumber)
      {
      case stat_godmode:
         return gamestate.SpecialsTimes.GodModeRespawnTime;

      case stat_dogmode:
         return gamestate.SpecialsTimes.DogModeRespawnTime;

      case stat_mushroom:
         return gamestate.SpecialsTimes.ShroomsModeRespawnTime;

      case stat_elastic:
         return gamestate.SpecialsTimes.ElastoModeRespawnTime;

      case stat_asbesto:
         return gamestate.SpecialsTimes.AsbestosVestRespawnTime;

      case stat_bulletproof:
         return gamestate.SpecialsTimes.BulletProofVestRespawnTime;

      case stat_gasmask:
         return gamestate.SpecialsTimes.GasMaskRespawnTime;

      case stat_fleetfeet:
         return gamestate.SpecialsTimes.MercuryModeRespawnTime;

      }

   return gamestate.BattleOptions.RespawnTime * VBLCOUNTER;


   }


/*
===================
=
= GetBonus
=
===================
*/
void GetBonus (objtype*ob,statobj_t *check)
{
	int heal;
	playertype * pstate;
   boolean randompowerup;

	M_LINKSTATE(ob,pstate);

   randompowerup=false;

randomlabel:
	switch (check->itemnumber)
	{

	case    stat_knifestatue:
      SD_PlaySoundRTP(SD_GETKNIFESND,ob->x, ob->y);
      if (ob==player)
         locplayerstate->HASKNIFE = 1;
      SD_PlaySoundRTP(PlayerSnds[locplayerstate->player], ob->x, ob->y);
      LocalBonusMessage("You found a knife.");
      break;
   case    stat_pedgoldkey:
      LocalBonusMessage("You found the \\EGold key.");
      goto keys;
   case    stat_pedsilverkey:
      LocalBonusMessage("You got the \\FSilver key.");
      goto keys;
   case    stat_pedironkey:
      LocalBonusMessage("You got the \\8Iron key.");
      goto keys;
   case    stat_pedcrystalkey:
      LocalBonusMessage("You got the \\4Oscuro key.");
keys:
		GiveKey (check->itemnumber - stat_pedgoldkey);
		SD_PlaySoundRTP (SD_GETKEYSND,ob->x, ob->y);
		break;
	case    stat_monkmeal:
		if (pstate->health == MaxHitpointsForCharacter(pstate))
			return;
		SD_PlaySoundRTP (SD_GETHEALTH1SND,ob->x, ob->y);
      LocalBonusMessage("You ate some Monk Meal.");
		HealPlayer (10,ob);
		gamestate.healthcount ++;
		break;
	case    stat_monkcrystal1:
		if (pstate->health == MaxHitpointsForCharacter(pstate))
			return;
		SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
      LocalBonusMessage("You picked up a small Monk Crystal.");

		HealPlayer (10,ob);
		gamestate.healthcount ++;
		break;
	case   stat_monkcrystal2:
		if (pstate->health == MaxHitpointsForCharacter(pstate))
			return;
      SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
      LocalBonusMessage("You picked up a large Monk Crystal.");

		HealPlayer (50,ob);
		gamestate.healthcount ++;
		break;
	case    stat_priestporridge:
		if (pstate->health == MaxHitpointsForCharacter(pstate))
			return;
      SD_PlaySoundRTP (SD_GETHEALTH1SND,ob->x, ob->y);
		if (check->flags & FL_ACTIVE)
         {
         HealPlayer (50,ob);
         LocalBonusMessage("You ate some Priest Porridge Hot.");
         }
		else
         {
         HealPlayer (20,ob);

         LocalBonusMessage("You ate some Priest Porridge.");
         }
		gamestate.healthcount ++;
		break;

	case   stat_healingbasin:
		if (pstate->health == MaxHitpointsForCharacter(pstate))
			return;
      SD_PlaySoundRTP (SD_GETHEALTH2SND,ob->x, ob->y);
		heal = 25 + (GameRandomNumber("GetBonus",0) >> 2);
		HealPlayer (heal,ob);
      LocalBonusMessage("You drank from the healing basin.");

		gamestate.healthcount ++;
		gamestate.democraticcount ++;
		break;

	case stat_oneup:
		if (abs(pstate->health - MaxHitpointsForCharacter(pstate))
			 < (MaxHitpointsForCharacter(pstate)>>2) )
         {
         GiveLives(1);
         LocalBonusMessage("Extra Life!");
         }
		else
         {
         HealPlayer(MaxHitpointsForCharacter(pstate),ob);
         LocalBonusMessage("Full Health!");
         }
		SD_PlaySoundRTP(SD_GET1UPSND,ob->x, ob->y);
		break;
	case stat_threeup:
		if (abs(pstate->health - MaxHitpointsForCharacter(pstate))
			 < (MaxHitpointsForCharacter(pstate)>>2) )
			{
         GiveLives(3);
         LocalBonusMessage("Three Extra Lives!");

			}
		else
         {
         HealPlayer(MaxHitpointsForCharacter(pstate),ob);
         GiveLives(2);
         LocalBonusMessage("Full Health AND Two Extra Lives!");

         }
		SD_PlaySoundRTP(SD_GET3UPSND,ob->x, ob->y);
		break;

   case stat_scotthead:
      // Give Apogee's phone number as points
      GivePoints( 2764331 );
      LocalBonusMessage( "Whoa...Scott's Mystical Head!");
      LocalBonus1Message( "You get 2,764,331 points!");
      SD_PlaySoundRTP(SD_GETHEADSND,ob->x, ob->y);
		break;

	case stat_twopistol:
      if (GiveBulletWeapon(ob,wp_twopistol,check)==false)
         return;
      LocalBonusMessage("You got an extra pistol.");

		break;
	case stat_mp40:
      if (GiveBulletWeapon(ob,wp_mp40,check)==false)
         return;
      LocalBonusMessage("You picked up an MP40.");

      break;

	case stat_bazooka:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You bagged a bazooka!");
      break;

   case stat_firebomb:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You found a Firebomb!");
      break;


	case stat_heatseeker:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You have a Heat-seeker!");
      break;


	case stat_drunkmissile:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You recovered a Drunk Missile!");
      break;

	case stat_firewall:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You filched a FlameWall!");
      break;

	case stat_splitmissile:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You snagged a Split Missile!");
      break;

	case stat_kes:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You wield the Dark Staff!");
      break;

	case stat_bat:
      if (GivePlayerMissileWeapon(ob,pstate,check)==false)
         return;

      LocalBonusMessage("You picked up the Excalibat.");
      break;


	case stat_lifeitem1:
      GiveLifePoints(ob,1);
      if (timelimitenabled)
         timelimit+=(VBLCOUNTER);

		break;

	case stat_lifeitem2:
      GiveLifePoints(ob,5);
      if (timelimitenabled)
         timelimit+=(2*VBLCOUNTER);
       break;

   case stat_lifeitem3:
      GiveLifePoints(ob,10);
      if (timelimitenabled)
         timelimit+=(5*VBLCOUNTER);
       break;

   case stat_lifeitem4:
      GiveLifePoints(ob,25);
      if (timelimitenabled)
         timelimit+=(10*VBLCOUNTER);
       break;

	case stat_random:
		switch (GameRandomNumber("GetBonus",0)>>6)
			{
			case 0:
				check->itemnumber=stat_godmode;
				break;
			case 1:
				check->itemnumber=stat_elastic;
				break;
			case 2:
				check->itemnumber=stat_dogmode;
				break;
			case 3:
				check->itemnumber=stat_mushroom;
				break;
			}
      randompowerup=true;
      LocalBonus1Message("Random powerup gives you . . .");
		goto randomlabel;
		break;

   case stat_bulletproof:
      GiveProtection(FL_BPV, GetBonusTimeForItem(stat_bulletproof),
         SD_GETBVESTSND);
      LocalBonusMessage("Bulletproof Armor!");

      goto drw;

	case stat_gasmask:
      GiveProtection(FL_GASMASK, GetBonusTimeForItem(stat_gasmask),
                     SD_GETMASKSND);
      LocalBonusMessage("You put on a Gas Mask.");

      goto drw;

	case stat_asbesto:
      GiveProtection(FL_AV,GetBonusTimeForItem(stat_asbesto),
                     SD_GETAVESTSND);
      LocalBonusMessage("Asbestos Armor! Oh so itchy!");

      goto drw;

   case stat_elastic:
      if (GivePowerup(ob,FL_ELASTO,GetBonusTimeForItem(stat_elastic),
                  SD_GETELASTSND) == false)
         return;
      LocalBonusMessage("Elasto Mode!");

      ob->flags |= FL_NOFRICTION;
      goto drw;

   case stat_fleetfeet:
      if (GivePowerup(ob,FL_FLEET,GetBonusTimeForItem(stat_fleetfeet),
                  SD_GETFLEETSND) == false)
         return;

      LocalBonus1Message("Mercury Mode!");
      LocalBonusMessage("Press Look Up and Down to fly.");

      ob->flags &= ~FL_NOFRICTION;
      goto drw;


   case stat_mushroom:
      if (GivePowerup(ob,FL_SHROOMS,GetBonusTimeForItem(stat_mushroom),
                  SD_GETSHROOMSSND) == false)
         return;
      LocalBonusMessage("Shrooms Mode!");

      ob->flags &= ~FL_NOFRICTION;
      gamestate.democraticcount ++;
      goto drw;


   case stat_godmode:

      if (ob->flags & FL_GODMODE)
         return;

      if (!ARMED(ob->dirchoosetime))
         return;

      ob->flags &= ~FL_NOFRICTION;

      if (ob->flags & FL_DOGMODE)
         {
         ob->temp2 = DOGMODERISE;
         ResetWeapons(ob);
         if (ob->state->condition & SF_DOGSTATE)
            NewState(ob,&s_player);
         }

      SaveWeapons(ob);
      SpawnNewObj(ob->tilex,ob->tiley,&s_flash1,inertobj);
      new->flags |= FL_ABP;
      new->x = new->drawx = ob->x;
      new->y = new->drawy = ob->y;
      MakeActive(new);
      new->z = ob->z;


      SetPlayerHorizon(pstate,GODYZANGLE);

      ob->flags &= ~(FL_GODMODE|FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_DOGMODE);
      ob->flags |= FL_GODMODE;
      ob->temp2 = GODMODERISE;
      pstate->poweruptime = GetBonusTimeForItem(stat_godmode);
      pstate->soundtime = 0;
      GiveMissileWeapon(ob,wp_godhand);
      SD_PlaySoundRTP(SD_GETGODSND,ob->x, ob->y);
      gamestate.supercount ++;
      LocalBonusMessage("God Mode!");

      goto drw;


#if (SHAREWARE == 0)
	case stat_dogmode:
      if (ob->flags & FL_DOGMODE)
         return;

      if (!ARMED(ob->dirchoosetime))
         return;

      ob->flags &= ~FL_NOFRICTION;

      if (ob->flags & FL_GODMODE)
         {
         ob->temp2 = GODMODEFALL;
         ResetWeapons(ob);
         }


      SaveWeapons(ob);
      ob->shapeoffset = 0;
      NewState(ob,&s_serialdog);

      SpawnNewObj(ob->tilex,ob->tiley,&s_flash1,inertobj);
      new->flags |= FL_ABP;
      new->x = new->drawx = ob->x;
      new->y = new->drawy = ob->y;
      MakeActive(new);
      new->z = ob->z;

      SetPlayerHorizon(pstate,DOGYZANGLE);

      ob->flags &= ~(FL_DOGMODE|FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_GODMODE);
      ob->flags |= FL_DOGMODE;
      ob->temp2 = DOGMODEFALL;
      pstate->poweruptime = GetBonusTimeForItem(stat_dogmode);
      pstate->soundtime = 0;
      GiveMissileWeapon(ob,wp_dog);
      SD_PlaySoundRTP(SD_GETDOGSND,ob->x, ob->y);
      gamestate.supercount ++;
      LocalBonusMessage("Dog Mode!");

      goto drw;
   #endif

 drw:

		if (ob==player)
         GM_DrawBonus (check->itemnumber);

		break;

	case stat_dipball1:
	case stat_dipball2:
	case stat_dipball3:
      SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);
		gamestate.dipballs++;
      LocalBonusMessage("You discovered a Developer Ball!");

	break;

   case stat_collector:
      if (gamestate.battlemode==battle_CaptureTheTriad)
        {if (pstate->team == check->hitpoints)
           return;
         ob->flags |= FL_DESIGNATED;
         UpdateKills = true;
         LocalBonusMessage( "You picked up a triad!  RUN!!!");
        }
      else
        BATTLE_CheckGameStatus(battle_get_collector_item,ob->dirchoosetime);

      SD_PlaySoundRTP(SD_GETBONUSSND,ob->x, ob->y);
		break;
#if (SHAREWARE == 0)
	case stat_mine:
		SpawnNewObj(check->tilex,check->tiley,&s_grexplosion1,inertobj);
		new->flags |= FL_ABP;
		new->whatever = check;
		new->temp2 = 100;
		MakeActive(new);
		SD_PlaySoundRTP(SD_EXPLODESND,check->x,check->y);
		break;
#endif
	default:
      SD_PlaySoundRTP(SD_GETHEADSND,ob->x, ob->y);
		break;
	}
	//StartBonusFlash ();
	if (check->flags & FL_CHANGES)
		{
		switch (check->itemnumber)
			{
			case stat_pedgoldkey:
			case stat_pedsilverkey:
			case stat_pedironkey:
			case stat_pedcrystalkey:
				check->itemnumber = stat_emptypedestal;
				check->shapenum = stats[stat_emptypedestal].picnum;
				check->flags = stats[stat_emptypedestal].flags|FL_ABP;
				check->count = 0;
				check->numanims = 0;
				break;
			case stat_healingbasin:
				check->itemnumber = stat_emptybasin;
				check->shapenum = stats[stat_emptybasin].picnum;
				check->flags = stats[stat_emptybasin].flags|FL_ABP;
				check->count = 0;
				check->numanims = 0;
				break;
			/*
				case stat_tablebullets:
				check->itemnumber = stat_emptytable;
				check->shapenum = stats[stat_emptytable].picnum;
				check->flags = stats[stat_emptytable].flags|FL_ABP;
				break;
			case stat_statuewithpole:
				check->itemnumber = stat_armornopole;
				check->shapenum = stats[stat_armornopole].picnum;
				check->flags = stats[stat_armornopole].flags|FL_ABP;
				break; */
			case stat_pit:
				check->shapenum ++;
				check->flags &= ~FL_CHANGES;
				check->flags &= ~FL_BONUS;
				break;
			case stat_knifestatue:
				check->itemnumber = stat_emptystatue;
				check->shapenum = stats[stat_emptystatue].picnum;
				check->flags = stats[stat_emptystatue].flags|FL_ABP;
				break;


			}
		}
	else
	  {if (check == sprites[check->tilex][check->tiley])
         {
         statobj_t *checkstat;

         checkstat = (statobj_t*)DiskAt(check->tilex,check->tiley);
         if (checkstat && (checkstat->which == SPRITE))
            sprites[check->tilex][check->tiley] = checkstat;
         else
            sprites[check->tilex][check->tiley] = NULL;
         }

      if (randompowerup==true)
         check->itemnumber = stat_random;
      RemoveStatic(check);
	  }
}


/*
===================
=
= DropWeapon
=
===================
*/

void DropWeapon(objtype *ob)
{playertype *pstate;
 int dtilex,dtiley;



 M_LINKSTATE(ob,pstate);

 if ((pstate->missileweapon == -1) || (pstate->missileweapon == wp_godhand)
#if (SHAREWARE == 0)
     || (pstate->missileweapon == wp_dog)
#endif
     )
	return;

 pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/3;
 pstate->new_weapon = pstate->bulletweapon;

 dtilex = ob->tilex;
 dtiley = ob->tiley;

 FindEmptyTile(&dtilex, &dtiley);


 SpawnStatic(dtilex,dtiley,GetItemForWeapon(pstate->missileweapon),9);
 gamestate.missiletotal ++;

 LASTSTAT->ammo = pstate->ammo;
 LASTSTAT->flags |= FL_ABP;
 LASTSTAT->flags &= ~FL_RESPAWN;
 MakeStatActive(LASTSTAT);
 pstate->weaponx = ob->tilex;
 pstate->weapony = ob->tiley;
 pstate->ammo = -1;
 pstate->missileweapon = -1;
 if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
	 DrawBarAmmo (false);
}


/*
===================
=
= Thrust
=
===================
*/

void Thrust ( objtype * ob )
{statobj_t *tstat;
 int dx,dy,dz,rad,index,otherteam;
 objtype*temp;
 playertype * pstate;

	PlayerMove(ob);
	M_LINKSTATE(ob,pstate);

	if ((gamestate.battlemode == battle_CaptureTheTriad) &&
		 (ob->flags & FL_DESIGNATED) &&
       (ob->tilex == TEAM[pstate->team].tilex) &&
       (ob->tiley == TEAM[pstate->team].tiley))
      {if (ob == player)
         SD_Play(PlayerSnds[locplayerstate->player]);

       if (BATTLE_CheckGameStatus(battle_captured_triad,ob->dirchoosetime)==
           battle_no_event)
          {
          ob->flags &= ~FL_DESIGNATED;
          UpdateKills = true;
          otherteam = (pstate->team ^ 1);
          SpawnStatic(TEAM[otherteam].tilex,TEAM[otherteam].tiley,stat_collector,9);
          LASTSTAT->flags |= FL_COLORED;
          LASTSTAT->hitpoints = otherteam;
          LASTSTAT->flags |= FL_ABP;
          MakeStatActive(LASTSTAT);
          }
       return;
		}

	if ((ob->tilex != pstate->weaponx) || (ob->tiley != pstate->weapony))
	  pstate->weaponx = pstate->weapony = 0;

   index = touchindices[ob->tilex][ob->tiley];
	if (index && (abs(ob->z - nominalheight) < 5))
	 {if (!TRIGGER[index-1])
		{if (touchplate[index-1]->complete)
			SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y);
		 else
         {
         SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y);
         if (ob == player)
            AddMessage("Touchplate triggered.",MSG_GAME);         }
		}
	  TRIGGER[index-1] = 1;
	 }

	tstat = sprites[ob->tilex][ob->tiley];
	if (tstat)

	 {dx = abs(ob->x - tstat->x);
	  dy = abs(ob->y - tstat->y);
	  dz = abs(ob->z - tstat->z);
     if ((dx < 0x8000) && (dy < 0x8000) && (dz<=35))
		{
#define OBJECT_IS_BONUS( tstat )                  ( ( tstat )->flags & FL_BONUS )
#define PLAYER_IS_SWITCHING_WEAPONS( pstate )     ( W_CHANGE( pstate ) )
//#define IS_ATTACKING( ob )                        ( ( ( ob )->state->think == T_Attack ) || ( ( ob )->state->think == T_BatBlast ) )
#define IS_WEAPON( tstat )                        ( ( tstat )->flags & FL_WEAPON )
#define PLAYER_MAY_NOT_GET_WEAPON( pstate, ob )   ( PLAYER_IS_SWITCHING_WEAPONS( pstate ))// || IS_ATTACKING( ob ) )
#define OK_TO_PICK_UP( tstat, pstate, ob )        ( !( IS_WEAPON( tstat ) && PLAYER_MAY_NOT_GET_WEAPON( pstate, ob ) ) )
#define WHERE_PLAYER_DROPPED_WEAPON( ob, pstate ) ( ( ( ob )->tilex == ( pstate )->weaponx ) && ( ( ob )->tiley == ( pstate )->weapony ) )

       if ( OBJECT_IS_BONUS( tstat ) &&
          OK_TO_PICK_UP( tstat, pstate, ob ) &&
          (!WHERE_PLAYER_DROPPED_WEAPON( ob, pstate ))
          )
          {
           GetBonus(ob,tstat);
           if (PLAYER_IS_SWITCHING_WEAPONS( pstate ))
             {statetype *nstate;
#if (SHAREWARE == 0)
              if (ob->state->condition & SF_DOGSTATE)
                nstate = &s_serialdog;
              else
#endif
                nstate = &s_player;
              pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
              NewState(ob,nstate);
             }


          }
       else if ((tstat->itemnumber == stat_pit) &&
                (ob->temp2 != PITFALL) &&
                (!(ob->flags & FL_FLEET))
               )
			 {ob->temp2 = PITFALL;
			  ob->momentumx = ob->momentumy = 0;
			  //ob->momentumz = 4;
			  ob->momentumz = GRAVITY;

			  if (ob->whatever == NULL)
				  {ob->whatever = tstat;
					SD_PlaySoundRTP(SD_PITTRAPSND,ob->x,ob->y);
					tstat->shapenum = stats[tstat->itemnumber].picnum + 1;
					MakeStatInactive(tstat);
			  //tstat->flags &= ~FL_ABP;
				  }
			 }
       else if ((tstat->itemnumber == stat_heatgrate) &&
                (!(ob->flags & FL_DYING)) && (!(ob->flags & FL_AV))
               )
			 {DamageThing(ob,1);
           Collision(ob,(objtype*)tstat,0,0);
           M_CheckPlayerKilled(ob);
			 }


		}
	 }

//================ Check special player/actor links ======================

   if (ob->whatever)
	 {temp = (objtype*)(ob->whatever);

		 dx = abs(ob->x - temp->x);
		 dy = abs(ob->y - temp->y);
       dz = abs(ob->z - temp->z);
		 if (ob->flags & FL_RIDING)
			rad = MINACTORDIST;
		 else
         rad = 0x8000;

       if ((dx >rad) || (dy > rad) || (dz > 64))
			{
         if ((temp->obclass == bladeobj) || (temp->obclass == diskobj))
			 {temp->whatever = NULL;
			  ob->flags &= ~FL_RIDING;
			 }

			else if (ob->temp2 == COLUMNCRUSH)
			  ob->temp2 = RENORMALIZE;
			else if (ob->z < nominalheight)
			  ob->momentumz = 40000;
			else if (temp->which == SPRITE)
			 {tstat = (statobj_t*)(ob->whatever);
			  MakeStatActive(tstat);
			  SetNormalHorizon(ob);
			 }
			ob->whatever = NULL;
			}
	 }

//=========================================================================


   if (BATTLEMODE && (MAPSPOT(ob->tilex,ob->tiley,1) == EXITTILE))
      {
      Move_Player_From_Exit_To_Start(ob);
      return;
      }

   if (ob==player)
		{
      if (MAPSPOT(ob->tilex,ob->tiley,1) == EXITTILE)
         playstate=ex_completed;
      else if ( ( MAPSPOT( ob->tilex, ob->tiley, 2 ) & 0xff00 ) == 0xe400 )
         playstate = ex_secretdone;
		else if (MAPSPOT(ob->tilex,ob->tiley,1) == SECRETEXITTILE)
			playstate=ex_secretlevel;
		}
}



void Move_Player_From_Exit_To_Start(objtype *ob)
   {
   int i = 0,oldarea,newarea;
   objtype *tplayer;
   int travelangle,dangle;
   playertype *pstate;

   M_LINKSTATE(ob,pstate);


   oldarea = ob->areanumber;
   newarea = AREANUMBER(FIRST.x,FIRST.y);
   if (oldarea != newarea)
      {
      RemoveFromArea(ob);
      ob->areanumber = newarea;
      MakeLastInArea(ob);
      }

   SetTilePosition(ob,FIRST.x,FIRST.y);
   ob->z = PlatformHeight(ob->tilex,ob->tiley);
   if ((ob->z == -10) || DiskAt(ob->tilex,ob->tiley))
      ob->z = 0;

   ConnectAreas();
   travelangle = atan2_appx(ob->momentumx,ob->momentumy);
   dangle = ob->angle - travelangle;

   ob->angle = (1-FIRST.dir)*ANG90 + dangle;
	Fix(ob->angle);

	ob->dir   = angletodir[ob->angle];
	pstate->anglefrac= (ob->angle<<ANGLEBITS);
	pstate->angle=0;


   for(i=0;i<numplayers;i++)
      {
      tplayer = PLAYER[i];

      if (ob == tplayer)
         continue;

      if (
         (tplayer->tilex == FIRST.x) &&
         (tplayer->tiley == FIRST.y) &&
         (!(tplayer->flags & FL_DYING))
         )
         {
         playertype *pstate;

         M_LINKSTATE(tplayer,pstate);

         pstate->health = tplayer->hitpoints = 0;
         tplayer->flags |= FL_HBM;
         Collision(tplayer,ob,0,0);
         BATTLE_PlayerKilledPlayer(battle_kill_by_crushing,ob->dirchoosetime,tplayer->dirchoosetime);\

         }
      }


   }



void PlayerSlideMove(objtype * ob)
{int tryx, tryy, tryz;

 tryx = ob->x + ob->momentumx;
 tryy = ob->y + ob->momentumy;
 tryz = ob->z + (ob->momentumz >> 16);

 if (ActorTryMove(ob,ob->x,tryy,tryz))
    {
	 if (ob->momentumx>HITWALLSPEED)
	    SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
    ob->momentumx=0;
    }
 else if (ActorTryMove(ob,tryx,ob->y,tryz))
    {
    if (ob->momentumy>HITWALLSPEED)
	    SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
	 ob->momentumy=0;
	 }
 else
    {
	 if (FindDistance(ob->momentumx,ob->momentumy)>(HITWALLSPEED*3/2))
	    SD_PlaySoundRTP(SD_HITWALLSND,ob->x,ob->y);
    ob->momentumx=0;
    ob->momentumy=0;
    }
}

/*
===================
=
= SetNormalHorizon
=
===================
*/

void SetNormalHorizon (objtype * ob)
{
	playertype * pstate;

	M_LINKSTATE(ob,pstate);

   if (ob->flags&FL_DOGMODE)
      {
      SetPlayerHorizon(pstate,DOGYZANGLE);
      }
   else if (ob->flags&FL_GODMODE)
      {
      SetPlayerHorizon(pstate,GODYZANGLE);
      }
   else
      {
      SetPlayerHorizon(pstate,NORMALYZANGLE);
      }
}

/*
===================
=
= PlayerTiltHead
=
===================
*/

void PlayerTiltHead (objtype * ob)
{
	playertype * pstate;
   int dyz=0;
   int yzangle;

	M_LINKSTATE(ob,pstate);

   yzangle=ob->yzangle+HORIZONYZOFFSET;
   Fix(yzangle);

   if (
        (pstate->lastmomz!=ob->momentumz) &&
        (ob->momentumz==0) &&
        (
          (!(ob->flags&FL_FLEET)) ||
          (
            (ob->flags&FL_FLEET) &&
            (ob->z==nominalheight)
          )
        )
      )
      SetNormalHorizon(ob);

   pstate->lastmomz=ob->momentumz;

   if (ob->flags&FL_SHROOMS)
      {
      ob->yzangle = FixedMulShift(SHROOMYZANGLE,sintable[(oldpolltime<<6)&(FINEANGLES-1)],16);
      Fix(ob->yzangle);
      return;
      }
   else if (pstate->guntarget)
      {
		int dx,dy,dz;
      int xydist;
      int yzangle;

      dx = ob->x - pstate->guntarget->x;
		dy = ob->y - pstate->guntarget->y;
      xydist = FindDistance(dx,dy)-0x8000;
      if (ob->z==pstate->guntarget->z)
         dz = 0;
      else
         {
         dz = (ob->z-pstate->guntarget->z)<<10;
         }
      yzangle = atan2_appx(xydist,dz);

      yzangle += HORIZONYZOFFSET;
      Fix(yzangle);
      SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);

		if (oldpolltime>pstate->targettime)
         {
         if (pstate->guntarget)
            pstate->guntarget->flags &= ~FL_TARGET;
			pstate->guntarget=NULL;
         SetNormalHorizon(ob);
         }
      }
   else
      {
      if (pstate->buttonstate[bt_horizonup])
         {
         if (yzangle!=pstate->horizon)
            {
            SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);
            }
         else
            {
            SetPlayerHorizon(pstate,(pstate->horizon-HORIZONYZOFFSET+YZHORIZONSPEED));
            }
         }
      else if (pstate->buttonstate[bt_horizondown])
         {
         if (yzangle!=pstate->horizon)
            {
            SetPlayerHorizon(pstate,yzangle-HORIZONYZOFFSET);
            }
         else
            {
            SetPlayerHorizon(pstate,(pstate->horizon-HORIZONYZOFFSET-YZHORIZONSPEED));
            }
         }
      if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
         {
         if (!(ob->flags & FL_FLEET))
            {
            dyz=YZTILTSPEED;
            if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
               {
               dyz=0;
               }

            SetNormalHorizon(ob);
            }
         }
      if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
         {
         if (!(ob->flags & FL_FLEET))
            {
            dyz=-YZTILTSPEED;
            if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
               {
               dyz=0;
               }
            SetNormalHorizon(ob);
            }
         }
      if (!(ob->flags&FL_DOGMODE) &&
               !(ob->flags&FL_GODMODE) &&
               !(ob->flags&FL_FLEET)   &&
               !(ob->flags&FL_RIDING)  &&
               (ob->momentumz > (GRAVITY<<1))//(ob->momentumz>0x1000)
            )
         {
         SetPlayerHorizon(pstate,FALLINGYZANGLE);
         }
      }



   if ((yzangle!=pstate->horizon) && (dyz==0))
      {
      int speed;

      speed=SNAPBACKSPEED;
		if (yzangle<pstate->horizon)
         yzangle+=speed;
		else
         yzangle-=speed;
      if ((abs(yzangle-pstate->horizon))<SNAPBACKSPEED)
         yzangle=pstate->horizon;
      }
   yzangle+=dyz;
   if (yzangle-HORIZONYZOFFSET>YZANGLELIMIT)
       yzangle=HORIZONYZOFFSET+YZANGLELIMIT;
   else if (yzangle-HORIZONYZOFFSET<-YZANGLELIMIT)
       yzangle=HORIZONYZOFFSET-YZANGLELIMIT;

   ob->yzangle=yzangle-HORIZONYZOFFSET;
   Fix(ob->yzangle);
}

/*
===================
=
= UpdatePlayers
=
===================
*/
void UpdatePlayers ( void )
{
   objtype * obj;
//   playertype * pstate;

	for (obj = FIRSTACTOR; obj->obclass==playerobj; obj = obj->next)
		 {
       obj->speed=FindDistance(obj->momentumx, obj->momentumy);
//       M_LINKSTATE(obj,pstate);
//       pstate->steptime-=obj->speed;
//       if (pstate->steptime<0)
//          {
//          while (pstate->steptime<0)
//             pstate->steptime+=PLAYERSTEPTIME;
//          pstate->stepwhich^=1;
//          SD_PlaySoundRTP(SD_WALK1SND+pstate->stepwhich,obj->x,obj->y);
//          }
		 }
}


/*
===================
=
= PlayerMove
=
===================
*/

void PlayerMove ( objtype * ob )
{playertype *pstate;

   M_LINKSTATE(ob,pstate);
   if (ob->flags & FL_FLEET)
      CheckFlying(ob,pstate);
   ActorMovement(ob);
   pstate->anglefrac = (pstate->anglefrac+pstate->angle)&((FINEANGLES<<ANGLEBITS)-1);
	ob->angle = (pstate->anglefrac >> ANGLEBITS);
	ob->dir = angletodir[ob->angle];
	if (ob==player)
		UpdateLightLevel(player->areanumber);

   PlayerTiltHead(ob);

   if (IsWindow(ob->tilex,ob->tiley))
		{
		if (!(ob->flags & FL_DYING))
			{
         pstate->health = 0;
         pstate->falling=true;
         if ((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE) ||
             (gamestate.battlemode == battle_Eluder) || (godmode==true))
            {
            KillActor(ob);
            NewState(ob,&s_remotedie1);
            }
         else
            Collision(ob,(objtype*)NULL,0,0);
         ob->flags |= FL_DYING;
         M_CheckPlayerKilled(ob);
			}
		}
}

/*
===============
=
= T_Tag
=
===============
*/

void  T_Tag (objtype *ob)
{
	playertype *pstate;

	CheckPlayerSpecials(ob);
	//CheckWeaponStates(ob);
	M_LINKSTATE(ob,pstate);
	Thrust(ob);

	if (ob->ticcount > 4)
		pstate->weaponheight -= GMOVE;
	else
		pstate->weaponheight += GMOVE;

	if ((ob->ticcount > 1) && (ob->ticcount < 8) && (!(ob->flags & FL_DIDTAG)))
	  {int i,dx,dy,magangle;

		for(i=0;i<numplayers;i++)
		  {if (PLAYER[i] == ob)
			  continue;

			dx = abs(PLAYER[i]->x - ob->x);
			dy = abs(PLAYER[i]->y - ob->y);
			if ((dx > 0xc000) || (dy > 0xc000))
			 continue;
			magangle = abs(ob->angle - AngleBetween(ob,PLAYER[i]));
			if (magangle > VANG180)
				magangle = ANGLES - magangle;

			if (magangle > ANGLES/8)
				continue;
         CheckTagGame(ob,PLAYER[i]);
			break;
		  }

	  }


//Commented out until we find if it's valid
/*
	if (!ob->ticcount)
	  {if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
			pstate->buttonstate[bt_use] = false;
		if ( pstate->buttonstate[bt_attack] && !pstate->buttonheld[bt_attack])
			pstate->buttonstate[bt_attack] = false;
	  }
*/
}

#if (SHAREWARE == 0)
#define GET_RESETSTATE(ob,resetstate)      \
   {                                       \
   if (ob->state->condition & SF_DOGSTATE) \
      resetstate = &s_serialdog;           \
   else                                    \
      resetstate = &s_player;              \
   }
#else
#define GET_RESETSTATE(ob,resetstate)      \
   {                                       \
   resetstate = &s_player;                 \
   }
#endif

/*
===============
=
= T_Attack
=
===============
*/

void  T_Attack (objtype *ob)
{
	attack_t   *cur;

	playertype *pstate;
   statetype *resetstate;


   Thrust(ob);
   if (ob->flags & FL_DYING)
     return;

   resetstate = ob->state;
   CheckPlayerSpecials(ob);
   if (resetstate != ob->state)
      {
      return;
      }


   if ((ob->flags & FL_PAIN) && (!ob->ticcount))
	  ob->flags &= ~FL_PAIN;

	CheckWeaponStates(ob);
	M_LINKSTATE(ob,pstate);
   GET_RESETSTATE(ob,resetstate);


   if (ARMED(ob->dirchoosetime)
   //(gamestate.battlemode != battle_Tag)
      )

      {
      if (pstate->weapondowntics == 1)  // change to up; during change, up and down
                                // are never zero at the same time
         {
   #if (SHAREWARE == 0)
         if (pstate->weapon == wp_kes)
            {
            pstate->weapondowntics = 0;
            pstate->weaponuptics = KESTICS/(2*GMOVE);
            }
         else
   #endif
            {
            pstate->weapondowntics = 0;
            pstate->weaponframe = pstate->attackframe = 0;

            if (pstate->NETCAPTURED == -1)
               {
               pstate->weaponuptics = FREE.screenheight/GMOVE;
               pstate->weaponheight = pstate->weaponuptics*GMOVE ;
               pstate->NETCAPTURED = 1;
     //          return;
               }
            else if (pstate->NETCAPTURED == -2)
               {
               pstate->weaponuptics = WEAPONS[pstate->weapon].screenheight/GMOVE;
               pstate->weaponheight = pstate->weaponuptics*GMOVE ;
               pstate->NETCAPTURED = 0;

              //return;
               }
            else
               {
               pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
               pstate->weapon = pstate->new_weapon;
               pstate->weaponheight = pstate->weaponuptics*GMOVE ;
               }
            }
         }
      }
  else if (gamestate.battlemode == battle_Hunter)
     {
     if (pstate->weapondowntics == 1)

        {
        pstate->weapondowntics = 0;
        pstate->weaponframe = pstate->attackframe = pstate->batblast = 0;
        pstate->weapon = pstate->new_weapon;
        NewState(ob,resetstate);
        return;
        }
     }




#if (SHAREWARE==0)
   if ((pstate->buttonstate[bt_use]) &&
       (pstate->weapon != wp_dog)
      )
#else
   if (pstate->buttonstate[bt_use])
#endif
		Cmd_Use (ob);

   if (pstate->attackframe >= WEAPONS[pstate->weapon].numattacks)
      Error("\n attackframe %d for weapon %d gt numattacks %d",
            pstate->attackframe,pstate->weapon,
            WEAPONS[pstate->weapon].numattacks
           );

   cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
	if (! pstate->attackcount)
      {
      switch (cur->attack)
         {
         case reset:
            if (vrenabled && (ob==player))
               {
               StopVRFeedback();
               }
            ob->flags &= ~FL_FULLLIGHT;
            if (pstate->ammo)
               {
               if (BATTLEMODE && (pstate->weapon == wp_firewall))
                  break;
               if (BATTLEMODE && (pstate->weapon == wp_firebomb))
                  break;
               if ((pstate->buttonstate[bt_attack]) && (pstate->weapon <= wp_firewall))
                  {
                  if (pstate->weapon <= wp_mp40)
                     {
                     if (pstate->weapon == wp_twopistol)
                        pstate->attackframe -= 6;
                     else if (pstate->weapon == wp_pistol)
                        pstate->attackframe -= 3;
                     else if (pstate->weapon == wp_mp40)
                        pstate->attackframe -= 2;

                     if (ob->state == &s_pmissattack2)
                        NewState(ob,&s_pmissattack1);
                     else if (ob->state == &s_pgunattack2)
                        NewState(ob,&s_pgunattack1);

                     }

                  }
               else
                  {
                  NewState(ob,resetstate);
                  pstate->attackframe = pstate->weaponframe = 0;
                  pstate->batblast = 0;
                  return;
                  }
               }
            else
               {
               NewState(ob,resetstate);
               pstate->attackframe = pstate->weaponframe = 0;
               pstate->new_weapon = pstate->bulletweapon;
               pstate->batblast = 0;
               pstate->ammo = -1;
               pstate->missileweapon = -1;
               pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;

               if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
                     DrawBarAmmo (false);

               return;
               }
            break;

         case reset2:
            if (vrenabled && (ob==player))
               {
               StopVRFeedback();
               }
            ob->flags &= ~FL_FULLLIGHT;
            if (pstate->buttonstate[bt_attack] && pstate->ammo)
               {
               pstate->attackframe -= 4;
               if (ob->state == &s_pmissattack2)
                  NewState(ob,&s_pmissattack1);
               else if (ob->state == &s_pgunattack2)
                  NewState(ob,&s_pgunattack1);
               }
            else
               {
               NewState(ob,resetstate);
               pstate->attackframe = pstate->weaponframe = 0;
               pstate->batblast = 0;
               return;
               }

            break;


         case at_pulltrigger:
            if (vrenabled && (ob==player))
               {
               StartVRFeedback(1);
               }
            ob->flags |= FL_FULLLIGHT;

      #if (SHAREWARE == 0)

            if (pstate->batblast >= BBTIME)
               DogBlast(ob);

            else if (pstate->weapon == wp_dog)
               DogAttack(ob);
            else if (pstate->weapon == wp_bat)
               BatAttack (ob);
            else
      #endif
               GunAttack(ob);

            break;

         case at_missileweapon:
            if (!pstate->ammo)
               {
               pstate->attackframe = pstate->weaponframe = 0;
               pstate->batblast = 0;
               return;
               }

            if (vrenabled && (ob==player))
               {
               StartVRFeedback(1);
               }
            ob->flags |= FL_FULLLIGHT;
            if (ob==player)
               SetIllumination(2);
            PlayerMissileAttack(ob);


            if (!(ob->flags & FL_GODMODE) && !godmode)
               {
               if (!BATTLEMODE || (gamestate.BattleOptions.Ammo != bo_infinite_shots))
                  pstate->ammo--;

               if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
                  DrawBarAmmo (false);
               }
   #if (SHAREWARE == 0)
            if (pstate->weapon == wp_kes)
               pstate->weapondowntics = KESTICS/(2*GMOVE);
   #endif
            break;

         }

      pstate->attackframe++;
      cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
      pstate->weaponframe = cur->frame;
      pstate->attackcount = cur->mtics;

      }
   else
      pstate->attackcount --;
   }

/*
===============
=
= T_BatBlast
=
===============
*/

void  T_BatBlast (objtype *ob)
{
	attack_t   *cur;
	playertype *pstate;


   Thrust(ob);
   CheckPlayerSpecials(ob);
   M_LINKSTATE(ob,pstate);


//Commented out until we find if it's valid
/*
	if (!ob->ticcount)
	 {if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
		pstate->buttonstate[bt_use] = false;

	  if ( pstate->buttonstate[bt_attack] && !pstate->buttonheld[bt_attack])
		pstate->buttonstate[bt_attack] = false;
	 }
*/
//
// change frame and fire
//

	BatBlast(ob);



   if (pstate->attackframe >= WEAPONS[pstate->weapon].numattacks)
      Error("\n attackframe %d for weapon %d gt numattacks %d",
            pstate->attackframe,pstate->weapon,
            WEAPONS[pstate->weapon].numattacks
           );



   cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
	if (! pstate->attackcount)
		{if (cur->attack == reset)
			{
			 if (!(ob->flags & FL_GODMODE) && (!godmode))
				{pstate->ammo --;
             if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
						DrawBarAmmo (false);
				}

			 if (!pstate->ammo)
				{pstate->new_weapon = pstate->bulletweapon;
				 pstate->ammo = -1;
				 pstate->missileweapon = -1;
				 pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;

				}

			 NewState(ob,&s_player);
			 pstate->attackframe = pstate->weaponframe = 0;
			 pstate->batblast = 0;
			 return;
			}
		 pstate->attackframe++;
		 pstate->weaponframe = WEAPONS[pstate->weapon].attackinfo[pstate->attackframe].frame;
		 cur = &(WEAPONS[pstate->weapon].attackinfo[pstate->attackframe]);
		 pstate->attackcount = cur->mtics;
		}
	else
		pstate->attackcount --;

}




void  T_Free (objtype *ob)
{
	attack_t   *cur;


  if (!ob->ticcount)
  {


//Commented out until we find if it's valid
/*
	if ( locplayerstate->buttonstate[bt_use] && !locplayerstate->buttonheld[bt_use] )
		locplayerstate->buttonstate[bt_use] = false;

	if ( locplayerstate->buttonstate[bt_attack] && !locplayerstate->buttonheld[bt_attack])
		locplayerstate->buttonstate[bt_attack] = false;
*/
   Thrust(ob);

  }
  CheckPlayerSpecials(ob);






  cur = &(FREE.attackinfo[locplayerstate->attackframe]);

	if (!locplayerstate->attackcount)
	 {
		if ((locplayerstate->weaponframe > 3) && (locplayerstate->weaponframe < 8))
		  locplayerstate->NETCAPTURED ++;
		else if (locplayerstate->weaponframe == 8)
		 {
			  locplayerstate->NETCAPTURED = -2;
			  MISCVARS->NET_IN_FLIGHT = false;
			  NewState(ob,&s_player);
			  locplayerstate->weapondowntics = FREE.screenheight/GMOVE;
		  return;
		 }

		locplayerstate->attackframe++;
		cur = &(FREE.attackinfo[locplayerstate->attackframe]);
		locplayerstate->weaponframe = cur->frame;

		locplayerstate->attackcount = cur->mtics;

	 }
	else
	 locplayerstate->attackcount --;
 }



void Switch_Who_Is_It_For_Tag(objtype *actor1,objtype *actor2)
{
 playertype *pstate;

 M_LINKSTATE(actor1,pstate);
 if (pstate->buttonstate[bt_use])
      {playertype *pstate2;

      M_LINKSTATE(actor2,pstate2);
      pstate2->oldmissileweapon = pstate2->oldweapon = pstate2->new_weapon =
      pstate2->missileweapon = pstate2->weapon = wp_godhand;
      pstate2->weaponheight = 144;
      pstate2->weaponuptics = (144 - TAGHANDHEIGHT)/GMOVE;
      pstate2->weapondowntics = 0;
      actor1->flags |= FL_DIDTAG;
      actor2->flags |= FL_DESIGNATED;
      UpdateKills = true;

      actor1->flags &= ~FL_DESIGNATED;
      BATTLE_PlayerKilledPlayer(battle_player_tagged,
         actor1->dirchoosetime, actor2->dirchoosetime);
      }

}



void CheckTagGame(objtype *actor1,objtype*actor2)
{
 //if ((actor1->obclass != playerobj) || (actor2->obclass != playerobj))
	//return;

 if (!BATTLEMODE)
	return;

 if (gamestate.battlemode != battle_Tag)
	return;

 SD_PlaySoundRTP(SD_GETBONUSSND,actor1->x,actor1->y);

 if (actor1->flags & FL_DESIGNATED)
   Switch_Who_Is_It_For_Tag(actor1,actor2);
 else if (actor2->flags & FL_DESIGNATED)
   Switch_Who_Is_It_For_Tag(actor2,actor1);

}






/*
======================
=
= CheckWeaponChange
=
= Keys 1-4 change weapons
=
======================
*/

void CheckWeaponChange (objtype * ob)
{
//   int     i;

	playertype * pstate;


	M_LINKSTATE(ob,pstate);
	//pstate = (ob == player)?(&playerstate):(&remoteplayerstate);
	if (W_CHANGE(pstate))
	 return;

	if (!ARMED(ob->dirchoosetime))
	  return;

	if ((ob->flags & FL_DOGMODE) || (ob->flags & FL_GODMODE))
		return;

#if (WEAPONCHEAT==1)
		if (godmode && Keyboard[sc_Insert])
			{
			SD_Play(SD_SELECTWPNSND);

			// FOR DEBUG only
			/*
			if (pstate->buttonstate[bt_run])
			 {
			 if (pstate->weapon == 0)
			  pstate->new_weapon = wp_bat;
			 else
			  pstate->new_weapon --;
			 }
			else
			 {*/
			 if (pstate->weapon == MAXWEAPONS-1)
			  pstate->new_weapon = 0;
			 else
			  pstate->new_weapon ++;
			 //}
			if (pstate->new_weapon <= wp_mp40)
			 {pstate->bulletweapon = pstate->new_weapon;
			  pstate->HASBULLETWEAPON[pstate->new_weapon] = 1;
			 }
			else
			 pstate->missileweapon = pstate->new_weapon;

         pstate->ammo = stats[GetItemForWeapon(pstate->missileweapon)].ammo;
         if (pstate->ammo<1)
            pstate->ammo=5;
         StartWeaponChange;
         //pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
         //if ((ob==player) && SHOW_BOTTOM_STATUS_BAR() )
			  //		DrawBarAmmo (false);
			}
		else if (pstate->buttonstate[bt_swapweapon])
#else
		if (pstate->buttonstate[bt_swapweapon])
#endif
		 {
		  if ((pstate->weapon == pstate->bulletweapon) &&
				(pstate->missileweapon != -1))
			  {pstate->new_weapon = pstate->missileweapon;
				StartWeaponChange;
			  }

		  else if (pstate->weapon != pstate->bulletweapon)
			{pstate->new_weapon = pstate->bulletweapon;
			 StartWeaponChange;
			}
		 }
      else if ((pstate->buttonstate[bt_dropweapon]) &&
         (!gamestate.BattleOptions.WeaponPersistence))
			{
			if (pstate->weapon==pstate->bulletweapon)
				{
				if ((ob==player) && (!(pstate->buttonheld[bt_dropweapon])))
               PlayNoWaySound();
				}
			else
				{
				if (sprites[ob->tilex][ob->tiley])
					{
					if ((ob==player) && (!(pstate->buttonheld[bt_dropweapon])))
                  PlayNoWaySound();
					}
				else
					{
					DropWeapon(ob);
					}
				}
			}



	 if (pstate->buttonstate[bt_pistol])
		{if (pstate->weapon != wp_pistol)
			{pstate->new_weapon = pstate->bulletweapon = wp_pistol;
			 StartWeaponChange;
			}
		}

	 else if (pstate->buttonstate[bt_dualpistol])
		{if ((pstate->weapon != wp_twopistol) && pstate->HASBULLETWEAPON[wp_twopistol])
			{pstate->new_weapon = pstate->bulletweapon = wp_twopistol;
			 StartWeaponChange;
			}
		}
	 else if (pstate->buttonstate[bt_mp40])
		{if ((pstate->weapon != wp_mp40) && pstate->HASBULLETWEAPON[wp_mp40])
			{pstate->new_weapon = pstate->bulletweapon = wp_mp40;
			 StartWeaponChange;
			}
		}
	 else if (pstate->buttonstate[bt_missileweapon])
		{if ((pstate->weapon != pstate->missileweapon) && (pstate->missileweapon != -1))
			{pstate->new_weapon = pstate->missileweapon;
			 StartWeaponChange;
			}
		}
}


void SetWhoHaveWeapons(void)
   {
   playertype *pstate;
   objtype    *ob;
   int        i;

   for ( i = 0; i < numplayers; i++ )
      {
      ob = PLAYER[ i ];
		M_LINKSTATE( ob, pstate );

		if ( ARMED( ob->dirchoosetime ))
         {
         if (pstate->weapon == -1)
            {
            if (( pstate->missileweapon != -1 ) && (pstate->ammo>0))
               pstate->new_weapon = pstate->missileweapon;

            else
               {
               if ( pstate->bulletweapon == -1 )
                  {
                  pstate->HASBULLETWEAPON[ wp_pistol ] = 1;
                  pstate->bulletweapon = wp_pistol;
                  }
               pstate->new_weapon = pstate->bulletweapon;
               pstate->ammo = -1;
               }

            pstate->weapon = pstate->new_weapon;
            pstate->weapondowntics = 0;
            pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
            pstate->weaponheight = pstate->weaponuptics*GMOVE ;
            pstate->attackframe = pstate->weaponframe =
            pstate->batblast = 0;
            if (i == consoleplayer)
               DrawBarAmmo(false);
            }
			}
		else
			{
			if (ob->flags & FL_DOGMODE)
            {
            ob->temp2 = DOGMODERISE;
            pstate->oldweapon = -1;
            ResetWeapons(ob);
            if (ob->state->condition & SF_DOGSTATE)
               NewState(ob,&s_player);
				}
			else if (ob->flags & FL_GODMODE)
            {
            ob->temp2 = GODMODEFALL;
            pstate->oldweapon = -1;
            ResetWeapons(ob);
				}
			else
            {
            pstate->new_weapon = -1;
            StartWeaponChange;
				}
         pstate->attackframe = pstate->weaponframe =
         pstate->batblast = 0;
			}
		}
	}








void CheckWeaponStates(objtype*ob)
{playertype *pstate;

 M_LINKSTATE(ob,pstate);

 if (gamestate.battlemode == battle_Tag)
	{if (pstate->weapondowntics)
		{pstate->weaponheight += GMOVE;
		 pstate->weapondowntics --;
		 if (!pstate->weapondowntics)
			pstate->weapon = pstate->missileweapon = pstate->bulletweapon =
			pstate->new_weapon = pstate->oldweapon = pstate->oldmissileweapon = -1;

		}


	 if (pstate->weaponuptics)
		{pstate->weaponheight -= GMOVE;
		 pstate->weaponuptics --;
		}
	 return;
	}

 if (pstate->weapondowntics)
		{pstate->weaponheight += GMOVE;
#if (SHAREWARE == 0)
       if ((pstate->weapon == wp_kes) && pstate->attackframe)
			pstate->weaponheight += GMOVE;
#endif
		 pstate->weapondowntics --;
		}
 else if (pstate->weaponuptics)
		{pstate->weaponheight -= GMOVE;
#if (SHAREWARE == 0)
       if ((pstate->weapon == wp_kes) && pstate->attackframe)
			pstate->weaponheight -= GMOVE;
#endif

       pstate->weaponuptics --;
		}
 else if ((pstate->weapon == pstate->new_weapon) && (!pstate->NETCAPTURED))
		pstate->weaponheight = 0;

}


/*
=============================
=
= CheckSpecialSounds
=
=============================
*/

#define REGDOGSTATE(ob) \
   ((ob->state == &s_serialdog) || (ob->state == &s_serialdog2) || \
    (ob->state == &s_serialdog3) || (ob->state == &s_serialdog4)   \
   )

static int dyingvolume=255;
void CheckSpecialSounds(objtype *ob, playertype *pstate)
   {
   int shift;

   if ((!BATTLEMODE) && (ob == player))
      {
      if (pstate->health < MaxHitpointsForCharacter(locplayerstate)/5)
         {
         pstate->healthtime ++;
         if (pstate->healthtime > 2*VBLCOUNTER)
            {
            pstate->healthtime = 0;
            SD_PlayPitchedSound ( SD_PLAYERDYINGSND, dyingvolume, 0 );
            if (dyingvolume>80)
               dyingvolume-=40;
            }
         }
      else
         {
         dyingvolume=255;
         }
      }

   if (((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE)) &&
       (!W_CHANGE(pstate))
      )
      {
      pstate->soundtime++;
      if (pstate->soundtime > (2*VBLCOUNTER))
         {
         int rand;

         rand = GameRandomNumber("player special sound",0);
         shift = (pstate->soundtime>>5);
         if ((rand << shift) > 3500)
            {
            int sound;

            pstate->soundtime = 0;

            rand = GameRandomNumber("player god scare",0);

            if (ob->flags & FL_GODMODE)
               {
               sound = SD_GODMODE1SND;
               if (rand < 160)
                  sound++;
               if (rand < 80)
                  sound ++;
               SD_PlaySoundRTP(sound,ob->x,ob->y);
               }
#if (SHAREWARE == 0)
            else if ((!pstate->batblast) && (!ob->momentumz) &&
                     (REGDOGSTATE(ob))
                    )
               {
               sound = SD_DOGMODEPANTSND;
               if (rand < 128)
                  sound += 2;
               NewState(ob,&s_doglick);
               pstate->attackframe = pstate->weaponframe =
               pstate->batblast = 0;
               SD_PlaySoundRTP(sound,ob->x,ob->y);
               }
#endif
            }
         }
      }




   else if (ob->flags & FL_GASMASK)
      {
      pstate->soundtime ++;

      if (pstate->soundtime > (3*VBLCOUNTER))
         {
         pstate->soundtime = 0;
			SD_PlaySoundRTP(SD_GASMASKSND,ob->x,ob->y);
         }
      }


   else if (MISCVARS->GASON)
      {
      pstate->soundtime ++;
      if (pstate->soundtime > (2*VBLCOUNTER))
         {
         int rand;

         rand = GameRandomNumber("player cough sound",0);
         shift = (pstate->soundtime>>5);
         if ((rand << shift) > 2000)
            {
            pstate->soundtime = 0;
            if ((pstate->player == 1) || (pstate->player == 3))
               SD_PlaySoundRTP(SD_PLAYERCOUGHFSND,ob->x,ob->y);
            else
               SD_PlaySoundRTP(SD_PLAYERCOUGHMSND,ob->x,ob->y);
            }
         }
      }
   }

/*
static int dyingvolume=255;
void CheckSpecialSounds(objtype *ob, playertype *pstate)
   {
   int shift;

   if ((!BATTLEMODE) && (ob == player))
      {
      if (pstate->health < MaxHitpointsForCharacter(locplayerstate)/5)
         {
         pstate->healthtime ++;
         if (pstate->healthtime > 2*VBLCOUNTER)
            {
            pstate->healthtime = 0;
            SD_PlayPitchedSound ( SD_PLAYERDYINGSND, dyingvolume, 0 );
            if (dyingvolume>80)
               dyingvolume-=40;
            }
         }
      else
         {
         dyingvolume=255;
         }
      }

   if (((ob->flags & FL_GODMODE) || (ob->flags & FL_DOGMODE)) &&
       (!W_CHANGE(pstate))
      )
      {
      pstate->soundtime++;
      if (pstate->soundtime > (2*VBLCOUNTER))
         {
         int rand;

         rand = GameRandomNumber("player special sound",0);
         shift = (pstate->soundtime>>5);
         if ((rand << shift) > 3500)
            {
            int sound;

            pstate->soundtime = 0;

            rand = GameRandomNumber("player god scare",0);

            if (ob->flags & FL_GODMODE)
               {
               sound = SD_GODMODE1SND;
               if (rand < 160)
                  sound++;
               if (rand < 80)
                  sound ++;
               SD_PlaySoundRTP(sound,ob->x,ob->y);
               }
#if (SHAREWARE == 0)
            else if (!pstate->batblast)
               {
               sound = SD_DOGMODEPANTSND;
               if (rand < 128)
                  sound += 2;
               NewState(ob,&s_doglick);
               pstate->attackframe = pstate->weaponframe =
               pstate->batblast = 0;
               SD_PlaySoundRTP(sound,ob->x,ob->y);
               }
#endif
            }
         }
      }




   else if (ob->flags & FL_GASMASK)
      {
      pstate->soundtime ++;

      if (pstate->soundtime > (3*VBLCOUNTER))
         {
         pstate->soundtime = 0;
			SD_PlaySoundRTP(SD_GASMASKSND,ob->x,ob->y);
         }
      }


   else if (MISCVARS->GASON)
      {
      pstate->soundtime ++;
      if (pstate->soundtime > (2*VBLCOUNTER))
         {
         int rand;

         rand = GameRandomNumber("player cough sound",0);
         shift = (pstate->soundtime>>5);
         if ((rand << shift) > 2000)
            {
            pstate->soundtime = 0;
            if ((pstate->player == 1) || (pstate->player == 3))
               SD_PlaySoundRTP(SD_PLAYERCOUGHFSND,ob->x,ob->y);
            else
               SD_PlaySoundRTP(SD_PLAYERCOUGHMSND,ob->x,ob->y);
            }
         }
      }
   }

*/


/*
=============================
=
= CheckProtectionsAndPowerups
=
=============================
*/



void CheckProtectionsAndPowerups(objtype *ob, playertype *pstate)
   {
	if (pstate->poweruptime)
		{
		pstate->poweruptime --;
		if (pstate->poweruptime < 0)
			pstate->poweruptime = 0;
		if (ob==player)
			GM_UpdateBonus (pstate->poweruptime, true);
		}
	else
		{
		if (ob->flags & FL_ELASTO)
			{
			ob->flags &= ~FL_NOFRICTION;
			if (ob==player)
				GM_UpdateBonus (pstate->poweruptime, true);
			SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
			}
		else if (ob->flags & FL_GODMODE)
			{ob->temp2 = GODMODEFALL;
          if ((pstate->player == 1) || (pstate->player == 3))
				SD_PlaySoundRTP(SD_GODWOMANSND,ob->x, ob->y);
			 else
				SD_PlaySoundRTP(SD_GODMANSND,ob->x, ob->y);
			 ResetWeapons(ob);
			}
		else if (ob->flags & FL_DOGMODE)
			{int wall;

			 wall = tilemap[ob->tilex][ob->tiley];
			 if ((wall & 0x4000) && (wall & 0x8000))
				{maskedwallobj_t * mw;

				 mw=maskobjlist[wall&0x3ff];
				 if (mw->flags&MW_NONDOGBLOCKING)
					return;
				}


			 ob->temp2 = DOGMODERISE;
          if ((pstate->player == 1) || (pstate->player == 3))
				SD_PlaySoundRTP(SD_DOGWOMANSND,ob->x, ob->y);
			 else
				SD_PlaySoundRTP(SD_DOGMANSND,ob->x, ob->y);
			 ResetWeapons(ob);
			 if (ob->state->condition & SF_DOGSTATE)
            {
            NewState(ob,&s_player);
            pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
            }
			}
		else if (ob->flags & FL_SHROOMS)
			{
			ResetFocalWidth ();
			SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
			}
		else if (ob->flags & FL_FLEET)
			SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);

      ob->flags &= ~(FL_SHROOMS|FL_ELASTO|FL_FLEET|FL_GODMODE|FL_DOGMODE);
		}

   if (pstate->protectiontime)
      {
      pstate->protectiontime --;
      if (pstate->protectiontime <= 0)
         {
         SD_PlaySoundRTP(SD_LOSEMODESND,ob->x, ob->y);
         pstate->protectiontime = 0;
         }
      if (ob==player)
         GM_UpdateBonus (pstate->protectiontime, false);
      }
   else
      ob->flags &= ~(FL_BPV|FL_AV|FL_GASMASK);

   }



/*
=============================
=
= CheckFlying
=
=============================
*/

void CheckFlying(objtype*ob,playertype *pstate)
   {


   if (pstate->buttonstate[bt_lookup] || CYBERLOOKUP)
      {
      ob->momentumz = -FLYINGZMOM;
      }
   if (pstate->buttonstate[bt_lookdown] || CYBERLOOKDOWN)
      {
      ob->momentumz = FLYINGZMOM;
      }

   /*
   if (!M_ISDOOR(((ob->x + costable[ob->angle])>>16),
         ((ob->y - sintable[ob->angle])>>16)) &&
         (pstate->buttonstate[bt_use]) &&
         (!pstate->buttonheld[bt_use])
      )
      {
      int op;
      int dist;

      dist=JETPACKTHRUST;
      if (ob->z-dist<-15)
         dist=ob->z+15;
      if (dist>0)
         {
         op = FixedMul(GRAVITY,(dist<<16)) << 1;
         ob->momentumz = -FixedSqrtHP(op);
         SD_PlaySoundRTP(SD_FLYINGSND,ob->x,ob->y);
         }
      }
   */
   }



/*
=============================
=
= CheckTemp2Codes
=
=============================
*/


#define IN_AIR(ob) \
             (!((ob->z == nominalheight) ||              \
                (IsPlatform(ob->tilex,ob->tiley)) ||    \
                (DiskAt(ob->tilex,ob->tiley))           \
               )                                        \
             )                                          \


void CheckTemp2Codes(objtype *ob,playertype *pstate)
   {
	int pitheight;
	int godheight;
	int dogheight;
	int height;
   int oldz;
   int destheightoffset;


	pitheight    = maxheight - 8;
	height = ob->z + pstate->playerheight;
	dogheight    = ob->z + DOGOFFSET;
	godheight    = ob->z + GODOFFSET;

   //SoftError("\nheightoffset: %d, temp2: %d",pstate->heightoffset,ob->temp2);


   if (!((ob->temp2 == PITFALL) || (ob->temp2 == PITRISE)))
      {

      oldz = ob->z;
      //SoftError("\n zmom %d, oldz %d, newz %d",ob->momentumz,oldz,ob->z);

      if (ob->flags & FL_FLEET)
         {
         if (IN_AIR(ob))
            pstate->heightoffset = FixedMulShift(0x4000,sintable[(oldpolltime<<6)&2047],28);

         ob->z += ((ob->momentumz+0x8000)>>16);
         ob->momentumz = 0;

         }
      else
         {
         ob->z += (ob->momentumz>>16);
         ob->momentumz += GRAVITY;
         }


      if (ob->z >= nominalheight)
         {
         ob->z = nominalheight;
         ob->momentumz = 0;
			 //if (platform == nominalheight)
			  //{//ob->temp2 = 0;
				//ob->momentumz = 0;
         if ((oldz < nominalheight) && (!(ob->flags & FL_RIDING)))
            {
				SD_PlaySoundRTP(SD_PLAYERLANDSND,ob->x,ob->y);
				}

         if (!(ob->flags & FL_ELASTO))
				ob->flags &= ~FL_NOFRICTION;
			//  }
			}
      else if (height < 1)
         {
         ob->momentumz = 0;
			ob->z = 1-pstate->playerheight;
         }



		switch (ob->temp2)
			{case RENORMALIZE:
				 pstate->heightoffset --;

             if (ob->flags & FL_DOGMODE)
                destheightoffset = DOGOFFSET-pstate->playerheight;
             else
                destheightoffset = 0;

             if (pstate->heightoffset <= destheightoffset)
               {
               ob->temp2 = 0;
               pstate->heightoffset = 0;
               }
				 pstate->oldheightoffset = pstate->heightoffset;

				 break;

			 case COLUMNCRUSH:
				 pstate->heightoffset += 4;
				 if (pstate->heightoffset >= 30)
					pstate->heightoffset = 30;

				 pstate->oldheightoffset = pstate->heightoffset;
				 break;

			 case GODMODERISE:
				 pstate->heightoffset --;
				 pstate->oldheightoffset = pstate->heightoffset;
				 if ((height+pstate->heightoffset) <= godheight)
					{
					 ob->temp2 = 0;
					 pstate->poweruptime = POWERUPTICS;
					}
				 break;


			 case GODMODEFALL:
				 pstate->heightoffset ++;
				 pstate->oldheightoffset = pstate->heightoffset;
				 SetPlayerHorizon(pstate,NORMALYZANGLE);
				 if (pstate->heightoffset >= 0)
				  {
					ob->temp2 = 0;
					ob->flags &= ~FL_GODMODE;
					SetNormalHorizon(ob);
				  }
				 break;

			 case DOGMODERISE:
				 pstate->heightoffset --;
				 pstate->oldheightoffset = pstate->heightoffset;
             SetPlayerHorizon(pstate,NORMALYZANGLE);
				 if (pstate->heightoffset <= 0)
					{
					 ob->temp2 = 0;
					 ob->flags &= ~FL_DOGMODE;
					 SetNormalHorizon(ob);
					}
				 break;


			 case DOGMODEFALL:
				 pstate->heightoffset ++;
				 pstate->oldheightoffset = pstate->heightoffset;
             if (pstate->heightoffset >= (DOGOFFSET-pstate->playerheight))
					 {
					 ob->temp2 = 0;
					 pstate->poweruptime = POWERUPTICS;
					 }
				 break;

          case STEPUP:
				 //Debug("\n\n heightoffset adjusted from %d to %d",
					//	 pstate->heightoffset,pstate->heightoffset - STEPADJUST);
				 pstate->heightoffset -= STEPADJUST;
				 if (pstate->heightoffset <= pstate->oldheightoffset)
					{ob->temp2 = 0;
					 //Debug("\n done adjusting heightoffset");
					 pstate->heightoffset = pstate->oldheightoffset;
					}
				 break;

			 case STEPDOWN:
				 pstate->heightoffset += STEPADJUST;
				 if (pstate->heightoffset >= pstate->oldheightoffset)
					{ob->temp2 = 0;
					 pstate->heightoffset = pstate->oldheightoffset;
					}
				 break;

          case 0:
             if (!((ob->flags & FL_FLEET) ||
                   (ob->flags & FL_DOGMODE) ||
                   (ob->flags & FL_GODMODE)
                  )
                )
                pstate->heightoffset = 0;
				 break;

			}


	  }


	else if (ob->temp2 == PITFALL)
		{
		if (ob->z != pitheight)
			{
			ob->z += (ob->momentumz>>16);
			ob->momentumz += GRAVITY;
			if (ob->z >= pitheight)
				{
				ob->z = pitheight;
				ob->momentumz = 0;
            if (!(ob->flags & FL_DYING))
               {DamageThing(ob,10);
                Collision(ob,(objtype*)NULL,0,0);
                M_CheckPlayerKilled(ob);
               }
				}
			}
		else if (ob->momentumx || ob->momentumy)
			{
			ob->temp2 = PITRISE;
			ob->momentumz = -2;
			}
		}

	else if (ob->temp2 == PITRISE)
		{ob->z += ob->momentumz;
		 if (ob->z <= nominalheight)
			 {ob->z = nominalheight;
			  ob->temp2 = 0;
			  ob->momentumz = 0;
           if (pstate->heightoffset)
              ob->temp2 = RENORMALIZE;
			 }
		}






   }



/*
=============================
=
= CheckRemoteRecording
=
=============================
*/

void CheckRemoteRecording(objtype *ob,playertype *pstate)
   {
   if (networkgame==true)
		{
		if ( (pstate->buttonstate[bt_recordsound]) &&
			  (!pstate->buttonheld[bt_recordsound])
			)
			{
			if (SD_RecordingActive()==false)
				{
				SD_SetRecordingActive ();
				PlayerRecording=ob->dirchoosetime;
				if (ob==player)
					{
                   SD_StartRecordingSound();
                   UpdateClientControls();
					}
				}
			}
		else if ( (pstate->buttonheld[bt_recordsound]) &&
					 (!pstate->buttonstate[bt_recordsound])
				  )
			{
			if (SD_RecordingActive()==true)
				{
				if (ob->dirchoosetime==PlayerRecording)
					{
					if (ob==player)
						SD_StopRecordingSound();
					SD_ClearRecordingActive();
					PlayerRecording=-1;
                   UpdateClientControls();
                   }
				}
			}
		}
   }


/*
=============================
=
= CheckPlayerSpecials
=
=============================
*/


void CheckPlayerSpecials(objtype * ob)
   {
	playertype * pstate;

	M_LINKSTATE(ob,pstate);

	// Check for recording of sound

   CheckRemoteRecording(ob,pstate);
   CheckTemp2Codes(ob,pstate);

	if (ob->flags & FL_DYING)
	  return;

   CheckSpecialSounds(ob,pstate);
   CheckProtectionsAndPowerups(ob,pstate);
   }

#if (SHAREWARE == 0)
/*
===============
=
= T_DogUse
=
===============
*/

void  T_DogUse (objtype *ob)
{
  attack_t   *cur;
  playertype *pstate;
  statetype *oldstate;

  M_LINKSTATE(ob,pstate);

  Thrust(ob);
  oldstate = ob->state;
  CheckPlayerSpecials(ob);
  if (ob->state != oldstate)
    {
    return;
    }




//Commented out until we find if it's valid
/*
  if (!ob->ticcount)
	{if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
		pstate->buttonstate[bt_use] = false;
	}
*/

   if (pstate->attackframe >= DOGSCRATCH.numattacks)
      Error("\n attackframe %d for DOGSCRATCH gt numattacks %d",
            pstate->attackframe,DOGSCRATCH.numattacks
           );



  cur = &(DOGSCRATCH.attackinfo[pstate->attackframe]);
  if (! pstate->attackcount)
	 {switch (cur->attack)
		 {case reset:
			  {
           NewState(ob,&s_dogwait);
           pstate->attackframe = pstate->weaponframe = pstate->batblast = 0;
			  return;
			  }
			  break;
		  case at_pulltrigger:
			 pstate->buttonheld[bt_use]=false;
          Cmd_Use(ob);
			 break;

		 }
	  pstate->attackframe++;
     cur = &(DOGSCRATCH.attackinfo[pstate->attackframe]);
     pstate->weaponframe = cur->frame;
	  pstate->attackcount = cur->mtics;

	 }
  else
	  pstate->attackcount --;



}

/*
===============
=
= T_DogLick
=
===============
*/



void  T_DogLick (objtype *ob)
{
  attack_t   *cur;
  playertype *pstate;
  statetype *oldstate;

  M_LINKSTATE(ob,pstate);

  Thrust(ob);
  oldstate = ob->state;
  CheckPlayerSpecials(ob);
  if (ob->state != oldstate)
    {
    return;
    }



//Commented out until we find if it's valid
/*
  if (!ob->ticcount)
	{if ( pstate->buttonstate[bt_use] && !pstate->buttonheld[bt_use] )
		pstate->buttonstate[bt_use] = false;
	}
*/


   if (pstate->attackframe >= DOGLICK.numattacks)
      Error("\n attackframe %d for DOGLICK gt numattacks %d",
            pstate->attackframe,DOGLICK.numattacks
           );


  cur = &(DOGLICK.attackinfo[pstate->attackframe]);
  if (! pstate->attackcount)
    {if (cur->attack == reset)
        {
        NewState(ob,&s_serialdog);
        pstate->attackframe = pstate->weaponframe = 0;
        return;
        }
	  pstate->attackframe++;
	  cur = &(DOGLICK.attackinfo[pstate->attackframe]);
	  pstate->weaponframe = cur->frame;
	  pstate->attackcount = cur->mtics;

	 }
  else
	  pstate->attackcount --;

 //	if ( playerstate.buttonstate[bt_attack] && (!playerstate.buttonheld[bt_attack]) && (!W_CHANGE))
  //		Cmd_Fire (ob);


}

#endif

void T_DeadWait(objtype*ob)
{
	playertype *pstate;

   M_LINKSTATE(ob,pstate);
   if ((ob->flags & FL_DESIGNATED) && (gamestate.battlemode == battle_CaptureTheTriad))
     {int otherteam = (pstate->team ^ 1);

      ob->flags &= ~FL_DESIGNATED;
      UpdateKills = true;
      SpawnStatic(TEAM[otherteam].tilex,TEAM[otherteam].tiley,stat_collector,9);
		LASTSTAT->flags |= FL_COLORED;
      LASTSTAT->hitpoints = otherteam;
      LASTSTAT->flags |= FL_ABP;
      MakeStatActive(LASTSTAT);

	  }
   //ob->momentumx=0;
   //ob->momentumy=0;

	if (pstate->heightoffset<36)
		{pstate->heightoffset++;
		 pstate->oldheightoffset = pstate->heightoffset;
		}

   if (ob==player)
      {
      UpdateLightLevel(player->areanumber);
      if ((pstate->falling==true) || (ob->momentumz==0))
         {
         if (BATTLEMODE)
				playerdead=true;
         else
			   playstate = ex_died;
         }
		}
	/*
   if (BATTLEMODE)
		{
		objtype * killer=(objtype *)ob->target;

		dx = killer->x - ob->x;
		dy = ob->y - killer->y;

		if (dx && dy)
			ob->angle = atan2_appx (dx,dy);
		}
	*/
	//CheckPlayerSpecials(ob);
}

/*
===============
=
= T_Player
=
===============
*/

void  T_Player (objtype *ob)
{
  playertype *pstate;
  statetype *oldstate;

#if (SHAREWARE == 0)
  int eluder;
#endif

  M_LINKSTATE(ob,pstate);



#if (SHAREWARE == 0)
  eluder = ((pstate->weapon == wp_dog) && gamestate.SpawnEluder);
#endif

  oldstate = ob->state;

  if (ob->flags&FL_DYING)
	  {

      CheckPlayerSpecials(ob);
      PlayerMove(ob);
      if (
          (pstate->falling==true) ||
          (
           (!ob->momentumx) &&
           (!ob->momentumy) &&
           (!ob->momentumz) &&
           (!ob->state->tictime)
          )
         )
		  {
			KillActor(ob);
			if (ob->state == &s_remoteguts12)
           NewState(ob,&s_gutwait);
			else
			  NewState(ob,&s_deadwait);
		  }
		return;
	  }

  Thrust(ob);
  if (ob->flags & FL_DYING)
    return;

  oldstate = ob->state;
  CheckPlayerSpecials(ob);
  if (ob->state != oldstate)
     {
     if (ob->flags & FL_DYING)
        return;
     }

  if (!(ob->flags & FL_PAIN))
	 {if (!(ob->state->condition & SF_DOGSTATE))
		 {if ((ob->momentumx || ob->momentumy) && (ob->state->condition != SF_DOWN))
			  NewState(ob,&s_remotemove1);
		  else if (NOMOM && (ob->state != &s_player))
			  NewState(ob,&s_player);
		 }
     else if (NOMOM
#if (SHAREWARE == 0)

     && (ob->state != &s_dogwait)
#endif

     )

         NewState(ob,ob->state);

	 }
  else if (!ob->ticcount)
    {if (!(ob->state->condition & SF_DOGSTATE))
		  NewState(ob,&s_player);

	  ob->flags &= ~FL_PAIN;

	 }

  if (ob->flags & FL_DIDTAG)
	{ob->flags &= ~FL_DIDTAG;
	 pstate->weapondowntics = (144 - TAGHANDHEIGHT)/GMOVE;
	}


  CheckWeaponStates(ob);


  if (ARMED(ob->dirchoosetime)
     //(gamestate.battlemode != battle_Tag)
     )
     {
     if (pstate->weapondowntics == 1)  // change to up; during change, up and down
									  // are never zero at the same time
        {
        pstate->weapondowntics = 0;
		  pstate->weaponframe = pstate->attackframe = 0;

		  if (pstate->NETCAPTURED == -1)
           {
			  pstate->weaponuptics = FREE.screenheight/GMOVE;
			  pstate->weaponheight = pstate->weaponuptics*GMOVE ;
			  pstate->NETCAPTURED = 1;
  //          return;
           }
		  else if (pstate->NETCAPTURED == -2)
           {
			  pstate->weaponuptics = WEAPONS[pstate->weapon].screenheight/GMOVE;
			  pstate->weaponheight = pstate->weaponuptics*GMOVE ;
			  pstate->NETCAPTURED = 0;

			  //return;
           }
		  else
           {
           pstate->weaponuptics = WEAPONS[pstate->new_weapon].screenheight/GMOVE;
           pstate->weapon = pstate->new_weapon;

           pstate->weaponheight = pstate->weaponuptics*GMOVE ;
			  }
        }

     else
        CheckWeaponChange (ob);
     }

  else if (gamestate.battlemode == battle_Hunter)
     {
     if (pstate->weapondowntics == 1)

        {
        pstate->weapondowntics = 0;
        pstate->weaponframe = pstate->attackframe = pstate->batblast = 0;
        pstate->weapon = pstate->new_weapon;
        }
     }

//   if ( pstate->buttonstate[bt_use] && (!W_CHANGE(pstate)) )

   if ( pstate->buttonstate[bt_use] )
      Cmd_Use (ob);


	if (W_CHANGE(pstate))
	  return;




   if ((!ARMED(ob->dirchoosetime))
#if (SHAREWARE == 0)
        && (pstate->weapon != wp_dog)
#endif
        )
		return;

	if (pstate->buttonstate[bt_attack])
      {
#if (SHAREWARE == 0)

      if (eluder)
			Cmd_Fire(ob);

      else if ((pstate->weapon == wp_bat) ||
               (pstate->weapon == wp_dog)
              )
         {
         int oldblast=pstate->batblast;

         pstate->batblast ++;

         if (pstate->weapon==wp_bat)
            {
            if (pstate->batblast == 20)
               SD_PlaySoundRTP(SD_EXCALIBUILDSND,ob->x,ob->y);
            }
         else
            {
            if ((pstate->batblast>>4)!=(oldblast>>4))
               {
               int handle;

               handle=SD_PlaySoundRTP(SD_DOGMODEPREPBLASTSND,ob->x,ob->y);
               SD_SetSoundPitch(handle,-(BBTIME<<3)+(pstate->batblast<<3));
               }
            }
         if (pstate->batblast < BBTIME)
			  return;

         if (pstate->weapon == wp_bat)
				SD_PlaySoundRTP(SD_EXCALIBLASTSND,ob->x,ob->y);
         else
            SD_PlaySoundRTP(SD_DOGMODEBLASTSND,ob->x,ob->y);
         }

      if ((pstate->weapon != wp_split) || (!pstate->buttonheld[bt_attack]))
#endif
  //    if (!pstate->buttonheld[bt_attack])
//#endif
         {

#if (SHAREWARE == 0)

         if (pstate->weapon == wp_kes)
			  SD_PlaySoundRTP(SD_GRAVBUILDSND,ob->x,ob->y);
#endif

			Cmd_Fire (ob);
         }
      }

#if (SHAREWARE == 0)

   else if (
             ((pstate->weapon == wp_bat) ||
              ((pstate->weapon == wp_dog) && (!eluder))
             ) &&
             (pstate->buttonheld[bt_attack])
           )
      {
      if (pstate->weapon == wp_bat)
         SD_StopSound(SD_EXCALIBUILDSND);
      pstate->batblast = 0;
      Cmd_Fire(ob);
      }
#endif

}



